/*******************************************************************************
* 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 License changed GPL-->LGPL 2011-12-16
*******************************************************************************/
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.Xml;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
using System.Diagnostics;
using OfficeOpenXml.Utils;
namespace OfficeOpenXml.Drawing
{
///
/// An image object
///
public sealed class ExcelPicture : ExcelDrawing
{
#region "Constructors"
internal ExcelPicture(ExcelDrawings drawings, XmlNode node) :
base(drawings, node, "xdr:pic/xdr:nvPicPr/xdr:cNvPr/@name")
{
XmlNode picNode = node.SelectSingleNode("xdr:pic/xdr:blipFill/a:blip", drawings.NameSpaceManager);
if (picNode != null)
{
RelPic = drawings.Part.GetRelationship(picNode.Attributes["r:embed"].Value);
UriPic = UriHelper.ResolvePartUri(drawings.UriDrawing, RelPic.TargetUri);
Part = drawings.Part.Package.GetPart(UriPic);
FileInfo f = new FileInfo(UriPic.OriginalString);
ContentType = GetContentType(f.Extension);
_image = Image.FromStream(Part.GetStream());
ImageConverter ic=new ImageConverter();
var iby=(byte[])ic.ConvertTo(_image, typeof(byte[]));
var ii = _drawings._package.LoadImage(iby, UriPic, Part);
ImageHash = ii.Hash;
string relID = GetXmlNodeString("xdr:pic/xdr:nvPicPr/xdr:cNvPr/a:hlinkClick/@r:id");
if (!string.IsNullOrEmpty(relID))
{
HypRel = drawings.Part.GetRelationship(relID);
if (HypRel.TargetUri.IsAbsoluteUri)
{
_hyperlink = new ExcelHyperLink(HypRel.TargetUri.AbsoluteUri);
}
else
{
_hyperlink = new ExcelHyperLink(HypRel.TargetUri.OriginalString, UriKind.Relative);
}
((ExcelHyperLink)_hyperlink).ToolTip = GetXmlNodeString("xdr:pic/xdr:nvPicPr/xdr:cNvPr/a:hlinkClick/@tooltip");
}
}
}
internal ExcelPicture(ExcelDrawings drawings, XmlNode node, Image image) :
this(drawings, node, image, null)
{
}
internal ExcelPicture(ExcelDrawings drawings, XmlNode node, Image image, Uri hyperlink) :
base(drawings, node, "xdr:pic/xdr:nvPicPr/xdr:cNvPr/@name")
{
XmlElement picNode = node.OwnerDocument.CreateElement("xdr", "pic", ExcelPackage.schemaSheetDrawings);
node.InsertAfter(picNode,node.SelectSingleNode("xdr:to",NameSpaceManager));
_hyperlink = hyperlink;
picNode.InnerXml = PicStartXml();
node.InsertAfter(node.OwnerDocument.CreateElement("xdr", "clientData", ExcelPackage.schemaSheetDrawings), picNode);
var package = drawings.Worksheet._package.Package;
//Get the picture if it exists or save it if not.
_image = image;
string relID = SavePicture(image);
//Create relationship
node.SelectSingleNode("xdr:pic/xdr:blipFill/a:blip/@r:embed", NameSpaceManager).Value = relID;
SetPosDefaults(image);
package.Flush();
}
internal ExcelPicture(ExcelDrawings drawings, XmlNode node, FileInfo imageFile) :
this(drawings,node,imageFile,null)
{
}
internal ExcelPicture(ExcelDrawings drawings, XmlNode node, FileInfo imageFile, Uri hyperlink) :
base(drawings, node, "xdr:pic/xdr:nvPicPr/xdr:cNvPr/@name")
{
XmlElement picNode = node.OwnerDocument.CreateElement("xdr", "pic", ExcelPackage.schemaSheetDrawings);
node.InsertAfter(picNode, node.SelectSingleNode("xdr:to", NameSpaceManager));
_hyperlink = hyperlink;
picNode.InnerXml = PicStartXml();
node.InsertAfter(node.OwnerDocument.CreateElement("xdr", "clientData", ExcelPackage.schemaSheetDrawings), picNode);
//Changed to stream 2/4-13 (issue 14834). Thnx SClause
var package = drawings.Worksheet._package.Package;
ContentType = GetContentType(imageFile.Extension);
var imagestream = new FileStream(imageFile.FullName, FileMode.Open, FileAccess.Read);
_image = Image.FromStream(imagestream);
ImageConverter ic = new ImageConverter();
var img = (byte[])ic.ConvertTo(_image, typeof(byte[]));
imagestream.Close();
UriPic = GetNewUri(package, "/xl/media/{0}" + imageFile.Name);
var ii = _drawings._package.AddImage(img, UriPic, ContentType);
string relID;
if(!drawings._hashes.ContainsKey(ii.Hash))
{
Part = ii.Part;
RelPic = drawings.Part.CreateRelationship(UriHelper.GetRelativeUri(drawings.UriDrawing, ii.Uri), Packaging.TargetMode.Internal, ExcelPackage.schemaRelationships + "/image");
relID = RelPic.Id;
_drawings._hashes.Add(ii.Hash, relID);
AddNewPicture(img, relID);
}
else
{
relID = drawings._hashes[ii.Hash];
var rel = _drawings.Part.GetRelationship(relID);
UriPic = UriHelper.ResolvePartUri(rel.SourceUri, rel.TargetUri);
}
SetPosDefaults(Image);
//Create relationship
node.SelectSingleNode("xdr:pic/xdr:blipFill/a:blip/@r:embed", NameSpaceManager).Value = relID;
package.Flush();
}
internal static string GetContentType(string extension)
{
switch (extension.ToLower(CultureInfo.InvariantCulture))
{
case ".bmp":
return "image/bmp";
case ".jpg":
case ".jpeg":
return "image/jpeg";
case ".gif":
return "image/gif";
case ".png":
return "image/png";
case ".cgm":
return "image/cgm";
case ".emf":
return "image/x-emf";
case ".eps":
return "image/x-eps";
case ".pcx":
return "image/x-pcx";
case ".tga":
return "image/x-tga";
case ".tif":
case ".tiff":
return "image/x-tiff";
case ".wmf":
return "image/x-wmf";
default:
return "image/jpeg";
}
}
//Add a new image to the compare collection
private void AddNewPicture(byte[] img, string relID)
{
var newPic = new ExcelDrawings.ImageCompare();
newPic.image = img;
newPic.relID = relID;
//_drawings._pics.Add(newPic);
}
#endregion
private string SavePicture(Image image)
{
ImageConverter ic = new ImageConverter();
byte[] img = (byte[])ic.ConvertTo(image, typeof(byte[]));
var ii = _drawings._package.AddImage(img);
if (_drawings._hashes.ContainsKey(ii.Hash))
{
var relID = _drawings._hashes[ii.Hash];
var rel = _drawings.Part.GetRelationship(relID);
UriPic = UriHelper.ResolvePartUri(rel.SourceUri, rel.TargetUri);
return relID;
}
else
{
UriPic = ii.Uri;
}
//Set the Image and save it to the package.
RelPic = _drawings.Part.CreateRelationship(UriHelper.GetRelativeUri(_drawings.UriDrawing, UriPic), Packaging.TargetMode.Internal, ExcelPackage.schemaRelationships + "/image");
//AddNewPicture(img, picRelation.Id);
_drawings._hashes.Add(ii.Hash, RelPic.Id);
ImageHash = ii.Hash;
return RelPic.Id;
}
private void SetPosDefaults(Image image)
{
EditAs = eEditAs.OneCell;
SetPixelWidth(image.Width, image.HorizontalResolution);
SetPixelHeight(image.Height, image.VerticalResolution);
}
private string PicStartXml()
{
StringBuilder xml = new StringBuilder();
xml.Append("");
if (_hyperlink == null)
{
xml.AppendFormat("", _id);
}
else
{
HypRel = _drawings.Part.CreateRelationship(_hyperlink, Packaging.TargetMode.External, ExcelPackage.schemaHyperlink);
xml.AppendFormat("", _id);
if (HypRel != null)
{
if (_hyperlink is ExcelHyperLink)
{
xml.AppendFormat("",
HypRel.Id, ((ExcelHyperLink)_hyperlink).ToolTip);
}
else
{
xml.AppendFormat("",
HypRel.Id);
}
}
xml.Append("");
}
xml.Append(" ");
return xml.ToString();
}
internal string ImageHash { get; set; }
Image _image = null;
///
/// The Image
///
public Image Image
{
get
{
return _image;
}
set
{
if (value != null)
{
_image = value;
try
{
string relID = SavePicture(value);
//Create relationship
TopNode.SelectSingleNode("xdr:pic/xdr:blipFill/a:blip/@r:embed", NameSpaceManager).Value = relID;
//_image.Save(Part.GetStream(FileMode.Create, FileAccess.Write), _imageFormat); //Always JPEG here at this point.
}
catch(Exception ex)
{
throw(new Exception("Can't save image - " + ex.Message, ex));
}
}
}
}
ImageFormat _imageFormat=ImageFormat.Jpeg;
///
/// Image format
/// If the picture is created from an Image this type is always Jpeg
///
public ImageFormat ImageFormat
{
get
{
return _imageFormat;
}
internal set
{
_imageFormat = value;
}
}
internal string ContentType
{
get;
set;
}
///
/// Set the size of the image in percent from the orginal size
/// Note that resizing columns / rows after using this function will effect the size of the picture
///
/// Percent
public override void SetSize(int Percent)
{
if(Image == null)
{
base.SetSize(Percent);
}
else
{
int width = Image.Width;
int height = Image.Height;
width = (int)(width * ((decimal)Percent / 100));
height = (int)(height * ((decimal)Percent / 100));
SetPixelWidth(width, Image.HorizontalResolution);
SetPixelHeight(height, Image.VerticalResolution);
}
}
internal Uri UriPic { get; set; }
internal Packaging.ZipPackageRelationship RelPic {get; set;}
internal Packaging.ZipPackageRelationship HypRel { get; set; }
internal Packaging.ZipPackagePart Part;
internal new string Id
{
get { return Name; }
}
ExcelDrawingFill _fill = null;
///
/// Fill
///
public ExcelDrawingFill Fill
{
get
{
if (_fill == null)
{
_fill = new ExcelDrawingFill(NameSpaceManager, TopNode, "xdr:pic/xdr:spPr");
}
return _fill;
}
}
ExcelDrawingBorder _border = null;
///
/// Border
///
public ExcelDrawingBorder Border
{
get
{
if (_border == null)
{
_border = new ExcelDrawingBorder(NameSpaceManager, TopNode, "xdr:pic/xdr:spPr/a:ln");
}
return _border;
}
}
private Uri _hyperlink = null;
///
/// Hyperlink
///
public Uri Hyperlink
{
get
{
return _hyperlink;
}
}
internal override void DeleteMe()
{
_drawings._package.RemoveImage(ImageHash);
base.DeleteMe();
}
public override void Dispose()
{
base.Dispose();
_hyperlink = null;
_image.Dispose();
_image = null;
}
}
}