/*******************************************************************************
* You may amend and distribute as you like, but don't remove this header!
*
* EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
* See http://www.codeplex.com/EPPlus for details.
*
* Copyright (C) 2011 Jan Källman
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
* If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
*
* All code and executables are provided "as is" with no warranty either express or implied.
* The author accepts no liability for any damage or loss of business that this product may cause.
*
* Code change notes:
*
* Author Change Date
*******************************************************************************
* Jan Källman Initial Release 2009-10-01
* Jan Källman Total rewrite 2010-03-01
* Jan Källman License changed GPL-->LGPL 2011-12-27
* *******************************************************************************/
using System;
using System.Xml;
using System.Text.RegularExpressions;
using System.Drawing;
using System.Collections.Generic;
using OfficeOpenXml.Drawing.Vml;
using System.IO;
using OfficeOpenXml.Drawing;
using OfficeOpenXml.Utils;
namespace OfficeOpenXml
{
///
/// How a picture will be aligned in the header/footer
///
public enum PictureAlignment
{
///
/// The picture will be added to the left aligned text
///
Left,
///
/// The picture will be added to the centered text
///
Centered,
///
/// The picture will be added to the right aligned text
///
Right
}
#region class ExcelHeaderFooterText
///
/// Print header and footer
///
public class ExcelHeaderFooterText
{
ExcelWorksheet _ws;
string _hf;
internal ExcelHeaderFooterText(XmlNode TextNode, ExcelWorksheet ws, string hf)
{
_ws = ws;
_hf = hf;
if (TextNode == null || string.IsNullOrEmpty(TextNode.InnerText)) return;
string text = TextNode.InnerText;
string code = text.Substring(0, 2);
int startPos=2;
for (int pos=startPos;pos
/// Get/set the text to appear on the left hand side of the header (or footer) on the worksheet.
///
public string LeftAlignedText = null;
///
/// Get/set the text to appear in the center of the header (or footer) on the worksheet.
///
public string CenteredText = null;
///
/// Get/set the text to appear on the right hand side of the header (or footer) on the worksheet.
///
public string RightAlignedText = null;
///
/// Inserts a picture at the end of the text in the header or footer
///
/// The image object containing the Picture
/// Alignment. The image object will be inserted at the end of the Text.
public ExcelVmlDrawingPicture InsertPicture(Image Picture, PictureAlignment Alignment)
{
string id = ValidateImage(Alignment);
//Add the image
ImageConverter ic = new ImageConverter();
byte[] img = (byte[])ic.ConvertTo(Picture, typeof(byte[]));
var ii = _ws.Workbook._package.AddImage(img);
return AddImage(Picture, id, ii);
}
///
/// Inserts a picture at the end of the text in the header or footer
///
/// The image object containing the Picture
/// Alignment. The image object will be inserted at the end of the Text.
public ExcelVmlDrawingPicture InsertPicture(FileInfo PictureFile, PictureAlignment Alignment)
{
string id = ValidateImage(Alignment);
Image Picture;
try
{
if (!PictureFile.Exists)
{
throw (new FileNotFoundException(string.Format("{0} is missing", PictureFile.FullName)));
}
Picture = Image.FromFile(PictureFile.FullName);
}
catch (Exception ex)
{
throw (new InvalidDataException("File is not a supported image-file or is corrupt", ex));
}
ImageConverter ic = new ImageConverter();
string contentType = ExcelPicture.GetContentType(PictureFile.Extension);
var uriPic = XmlHelper.GetNewUri(_ws._package.Package, "/xl/media/"+PictureFile.Name.Substring(0, PictureFile.Name.Length-PictureFile.Extension.Length) + "{0}" + PictureFile.Extension);
byte[] imgBytes = (byte[])ic.ConvertTo(Picture, typeof(byte[]));
var ii = _ws.Workbook._package.AddImage(imgBytes, uriPic, contentType);
return AddImage(Picture, id, ii);
}
private ExcelVmlDrawingPicture AddImage(Image Picture, string id, ExcelPackage.ImageInfo ii)
{
double width = Picture.Width * 72 / Picture.HorizontalResolution, //Pixel --> Points
height = Picture.Height * 72 / Picture.VerticalResolution; //Pixel --> Points
//Add VML-drawing
return _ws.HeaderFooter.Pictures.Add(id, ii.Uri, "", width, height);
}
private string ValidateImage(PictureAlignment Alignment)
{
string id = string.Concat(Alignment.ToString()[0], _hf);
foreach (ExcelVmlDrawingPicture image in _ws.HeaderFooter.Pictures)
{
if (image.Id == id)
{
throw (new InvalidOperationException("A picture already exists in this section"));
}
}
//Add the image placeholder to the end of the text
switch (Alignment)
{
case PictureAlignment.Left:
LeftAlignedText += ExcelHeaderFooter.Image;
break;
case PictureAlignment.Centered:
CenteredText += ExcelHeaderFooter.Image;
break;
default:
RightAlignedText += ExcelHeaderFooter.Image;
break;
}
return id;
}
}
#endregion
#region ExcelHeaderFooter
///
/// Represents the Header and Footer on an Excel Worksheet
///
public sealed class ExcelHeaderFooter : XmlHelper
{
#region Static Properties
///
/// The code for "current page #"
///
public const string PageNumber = @"&P";
///
/// The code for "total pages"
///
public const string NumberOfPages = @"&N";
///
/// The code for "text font color"
/// RGB Color is specified as RRGGBB
/// Theme Color is specified as TTSNN where TT is the theme color Id, S is either "+" or "-" of the tint/shade value, NN is the tint/shade value.
///
public const string FontColor = @"&K";
///
/// The code for "sheet tab name"
///
public const string SheetName = @"&A";
///
/// The code for "this workbook's file path"
///
public const string FilePath = @"&Z";
///
/// The code for "this workbook's file name"
///
public const string FileName = @"&F";
///
/// The code for "date"
///
public const string CurrentDate = @"&D";
///
/// The code for "time"
///
public const string CurrentTime = @"&T";
///
/// The code for "picture as background"
///
public const string Image = @"&G";
///
/// The code for "outline style"
///
public const string OutlineStyle = @"&O";
///
/// The code for "shadow style"
///
public const string ShadowStyle = @"&H";
#endregion
#region ExcelHeaderFooter Private Properties
internal ExcelHeaderFooterText _oddHeader;
internal ExcelHeaderFooterText _oddFooter;
internal ExcelHeaderFooterText _evenHeader;
internal ExcelHeaderFooterText _evenFooter;
internal ExcelHeaderFooterText _firstHeader;
internal ExcelHeaderFooterText _firstFooter;
private ExcelWorksheet _ws;
#endregion
#region ExcelHeaderFooter Constructor
///
/// ExcelHeaderFooter Constructor
///
///
///
/// The worksheet
internal ExcelHeaderFooter(XmlNamespaceManager nameSpaceManager, XmlNode topNode, ExcelWorksheet ws) :
base(nameSpaceManager, topNode)
{
_ws = ws;
SchemaNodeOrder = new string[] { "headerFooter", "oddHeader", "oddFooter", "evenHeader", "evenFooter", "firstHeader", "firstFooter" };
}
#endregion
#region alignWithMargins
const string alignWithMarginsPath="@alignWithMargins";
///
/// Gets/sets the alignWithMargins attribute
///
public bool AlignWithMargins
{
get
{
return GetXmlNodeBool(alignWithMarginsPath);
}
set
{
SetXmlNodeString(alignWithMarginsPath, value ? "1" : "0");
}
}
#endregion
#region differentOddEven
const string differentOddEvenPath = "@differentOddEven";
///
/// Gets/sets the flag that tells Excel to display different headers and footers on odd and even pages.
///
public bool differentOddEven
{
get
{
return GetXmlNodeBool(differentOddEvenPath);
}
set
{
SetXmlNodeString(differentOddEvenPath, value ? "1" : "0");
}
}
#endregion
#region differentFirst
const string differentFirstPath = "@differentFirst";
///
/// Gets/sets the flag that tells Excel to display different headers and footers on the first page of the worksheet.
///
public bool differentFirst
{
get
{
return GetXmlNodeBool(differentFirstPath);
}
set
{
SetXmlNodeString(differentFirstPath, value ? "1" : "0");
}
}
#endregion
#region ExcelHeaderFooter Public Properties
///
/// Provides access to the header on odd numbered pages of the document.
/// If you want the same header on both odd and even pages, then only set values in this ExcelHeaderFooterText class.
///
public ExcelHeaderFooterText OddHeader
{
get
{
if (_oddHeader == null)
{
_oddHeader = new ExcelHeaderFooterText(TopNode.SelectSingleNode("d:oddHeader", NameSpaceManager), _ws, "H");
}
return _oddHeader; }
}
///
/// Provides access to the footer on odd numbered pages of the document.
/// If you want the same footer on both odd and even pages, then only set values in this ExcelHeaderFooterText class.
///
public ExcelHeaderFooterText OddFooter
{
get
{
if (_oddFooter == null)
{
_oddFooter = new ExcelHeaderFooterText(TopNode.SelectSingleNode("d:oddFooter", NameSpaceManager), _ws, "F"); ;
}
return _oddFooter;
}
}
// evenHeader and evenFooter set differentOddEven = true
///
/// Provides access to the header on even numbered pages of the document.
///
public ExcelHeaderFooterText EvenHeader
{
get
{
if (_evenHeader == null)
{
_evenHeader = new ExcelHeaderFooterText(TopNode.SelectSingleNode("d:evenHeader", NameSpaceManager), _ws, "HEVEN");
differentOddEven = true;
}
return _evenHeader;
}
}
///
/// Provides access to the footer on even numbered pages of the document.
///
public ExcelHeaderFooterText EvenFooter
{
get
{
if (_evenFooter == null)
{
_evenFooter = new ExcelHeaderFooterText(TopNode.SelectSingleNode("d:evenFooter", NameSpaceManager), _ws, "FEVEN");
differentOddEven = true;
}
return _evenFooter ;
}
}
///
/// Provides access to the header on the first page of the document.
///
public ExcelHeaderFooterText FirstHeader
{
get
{
if (_firstHeader == null)
{
_firstHeader = new ExcelHeaderFooterText(TopNode.SelectSingleNode("d:firstHeader", NameSpaceManager), _ws, "HFIRST");
differentFirst = true;
}
return _firstHeader;
}
}
///
/// Provides access to the footer on the first page of the document.
///
public ExcelHeaderFooterText FirstFooter
{
get
{
if (_firstFooter == null)
{
_firstFooter = new ExcelHeaderFooterText(TopNode.SelectSingleNode("d:firstFooter", NameSpaceManager), _ws, "FFIRST");
differentFirst = true;
}
return _firstFooter;
}
}
private ExcelVmlDrawingPictureCollection _vmlDrawingsHF = null;
///
/// Vml drawings. Underlaying object for Header footer images
///
public ExcelVmlDrawingPictureCollection Pictures
{
get
{
if (_vmlDrawingsHF == null)
{
var vmlNode = _ws.WorksheetXml.SelectSingleNode("d:worksheet/d:legacyDrawingHF/@r:id", NameSpaceManager);
if (vmlNode == null)
{
_vmlDrawingsHF = new ExcelVmlDrawingPictureCollection(_ws._package, _ws, null);
}
else
{
if (_ws.Part.RelationshipExists(vmlNode.Value))
{
var rel = _ws.Part.GetRelationship(vmlNode.Value);
var vmlUri = UriHelper.ResolvePartUri(rel.SourceUri, rel.TargetUri);
_vmlDrawingsHF = new ExcelVmlDrawingPictureCollection(_ws._package, _ws, vmlUri);
_vmlDrawingsHF.RelId = rel.Id;
}
}
}
return _vmlDrawingsHF;
}
}
#endregion
#region Save // ExcelHeaderFooter
///
/// Saves the header and footer information to the worksheet XML
///
internal void Save()
{
if (_oddHeader != null)
{
SetXmlNodeString("d:oddHeader", GetText(OddHeader));
}
if (_oddFooter != null)
{
SetXmlNodeString("d:oddFooter", GetText(OddFooter));
}
// only set evenHeader and evenFooter
if (differentOddEven)
{
if (_evenHeader != null)
{
SetXmlNodeString("d:evenHeader", GetText(EvenHeader));
}
if (_evenFooter != null)
{
SetXmlNodeString("d:evenFooter", GetText(EvenFooter));
}
}
// only set firstHeader and firstFooter
if (differentFirst)
{
if (_firstHeader != null)
{
SetXmlNodeString("d:firstHeader", GetText(FirstHeader));
}
if (_firstFooter != null)
{
SetXmlNodeString("d:firstFooter", GetText(FirstFooter));
}
}
}
internal void SaveHeaderFooterImages()
{
if (_vmlDrawingsHF != null)
{
if (_vmlDrawingsHF.Count == 0)
{
if (_vmlDrawingsHF.Uri != null)
{
_ws.Part.DeleteRelationship(_vmlDrawingsHF.RelId);
_ws._package.Package.DeletePart(_vmlDrawingsHF.Uri);
}
}
else
{
if (_vmlDrawingsHF.Uri == null)
{
_vmlDrawingsHF.Uri = XmlHelper.GetNewUri(_ws._package.Package, @"/xl/drawings/vmlDrawing{0}.vml");
}
if (_vmlDrawingsHF.Part == null)
{
_vmlDrawingsHF.Part = _ws._package.Package.CreatePart(_vmlDrawingsHF.Uri, "application/vnd.openxmlformats-officedocument.vmlDrawing", _ws._package.Compression);
var rel = _ws.Part.CreateRelationship(UriHelper.GetRelativeUri(_ws.WorksheetUri, _vmlDrawingsHF.Uri), Packaging.TargetMode.Internal, ExcelPackage.schemaRelationships + "/vmlDrawing");
_ws.SetHFLegacyDrawingRel(rel.Id);
_vmlDrawingsHF.RelId = rel.Id;
foreach (ExcelVmlDrawingPicture draw in _vmlDrawingsHF)
{
rel = _vmlDrawingsHF.Part.CreateRelationship(UriHelper.GetRelativeUri(_vmlDrawingsHF.Uri, draw.ImageUri), Packaging.TargetMode.Internal, ExcelPackage.schemaRelationships + "/image");
draw.RelId = rel.Id;
}
}
_vmlDrawingsHF.VmlDrawingXml.Save(_vmlDrawingsHF.Part.GetStream());
}
}
}
private string GetText(ExcelHeaderFooterText headerFooter)
{
string ret = "";
if (headerFooter.LeftAlignedText != null)
ret += "&L" + headerFooter.LeftAlignedText;
if (headerFooter.CenteredText != null)
ret += "&C" + headerFooter.CenteredText;
if (headerFooter.RightAlignedText != null)
ret += "&R" + headerFooter.RightAlignedText;
return ret;
}
#endregion
}
#endregion
}