Related
What I am trying to do is adding two context menus, "Copy to Grayscale" and "List all images".
I pass a parameter "List"/"Copy" to distinguish them.
string menuCommand = string.Format("\"{0}\"{1}\" \"%L\" CopyGrayscaleImage", " List", Application.ExecutablePath);
But this is wrong.
What the menuCommand line should look like and how to handle it in the Main method ?
This is the class FileShellExtensions
using System;
using System.Diagnostics;
using Microsoft.Win32;
namespace SimpleContextMenu
{
/// <summary>
/// Register and unregister simple shell context menus.
/// </summary>
static class FileShellExtension
{
/// <summary>
/// Register a simple shell context menu.
/// </summary>
/// <param name="fileType">The file type to register.</param>
/// <param name="shellKeyName">Name that appears in the registry.</param>
/// <param name="menuText">Text that appears in the context menu.</param>
/// <param name="menuCommand">Command line that is executed.</param>
public static void Register(
string fileType, string shellKeyName,
string menuText, string menuCommand)
{
Debug.Assert(!string.IsNullOrEmpty(fileType) &&
!string.IsNullOrEmpty(shellKeyName) &&
!string.IsNullOrEmpty(menuText) &&
!string.IsNullOrEmpty(menuCommand));
// create full path to registry location
string regPath = string.Format(#"{0}\shell\{1}", fileType, shellKeyName);
// add context menu to the registry
using (RegistryKey key = Registry.ClassesRoot.CreateSubKey(regPath))
{
key.SetValue(null, menuText);
}
// add command that is invoked to the registry
using (RegistryKey key = Registry.ClassesRoot.CreateSubKey(
string.Format(#"{0}\command", regPath)))
{
key.SetValue(null, menuCommand);
}
}
/// <summary>
/// Unregister a simple shell context menu.
/// </summary>
/// <param name="fileType">The file type to unregister.</param>
/// <param name="shellKeyName">Name that was registered in the registry.</param>
public static void Unregister(string fileType, string shellKeyName)
{
Debug.Assert(!string.IsNullOrEmpty(fileType) &&
!string.IsNullOrEmpty(shellKeyName));
// full path to the registry location
string regPath = string.Format(#"{0}\shell\{1}", fileType, shellKeyName);
// remove context menu from the registry
Registry.ClassesRoot.DeleteSubKeyTree(regPath);
}
}
}
This is the Progrsm.cs
using System;
using System.Windows.Forms;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
[assembly: CLSCompliant(true)]
namespace SimpleContextMenu
{
static class Program
{
// file type to register
const string FileType = "jpegfile";
// context menu name in the registry
const string KeyName = "Simple Context Menu";
const string KeyName1 = "Simple Context Menu1";
// context menu text
const string MenuText = "Copy to Grayscale";
const string MenuText1 = "List all images";
[STAThread]
static void Main(string[] args)
{
// process register or unregister commands
if (!ProcessCommand(args))
{
// invoked from shell, process the selected file
CopyGrayscaleImage(args[0]);
}
}
/// <summary>
/// Process command line actions (register or unregister).
/// </summary>
/// <param name="args">Command line arguments.</param>
/// <returns>True if processed an action in the command line.</returns>
static bool ProcessCommand(string[] args)
{
// register
if (args.Length == 0 || string.Compare(args[0], "-register", true) == 0)
{
// full path to self, %L is placeholder for selected file
//string menuCommand = string.Format(
//"\"{0}\" \"%L\"", Application.ExecutablePath);
string menuCommand = string.Format("\"{0}\"{1}\" \"%L\" CopyGrayscaleImage", " List", Application.ExecutablePath);
// register the context menu
FileShellExtension.Register(Program.FileType,
Program.KeyName, Program.MenuText,
menuCommand);
FileShellExtension.Register(Program.FileType,
Program.KeyName1, Program.MenuText1,
menuCommand);
MessageBox.Show(string.Format(
"The {0} shell extension was registered.",
Program.KeyName), Program.KeyName);
return true;
}
// unregister
if (string.Compare(args[0], "-unregister", true) == 0)
{
// unregister the context menu
FileShellExtension.Unregister(Program.FileType, Program.KeyName);
MessageBox.Show(string.Format(
"The {0} shell extension was unregistered.",
Program.KeyName), Program.KeyName);
return true;
}
// command line did not contain an action
return false;
}
/// <summary>
/// Make a grayscale copy of the image.
/// </summary>
/// <param name="filePath">Full path to the image to copy.</param>
static void CopyGrayscaleImage(string filePath)
{
try
{
// full path to the grayscale copy
string grayFilePath = Path.Combine(
Path.GetDirectoryName(filePath),
string.Format("{0} (grayscale){1}",
Path.GetFileNameWithoutExtension(filePath),
Path.GetExtension(filePath)));
// using calls Dispose on the objects, important
// so the file is not locked when the app terminates
using (Image image = new Bitmap(filePath))
using (Bitmap grayImage = new Bitmap(image.Width, image.Height))
using (Graphics g = Graphics.FromImage(grayImage))
{
// setup grayscale matrix
ImageAttributes attr = new ImageAttributes();
attr.SetColorMatrix(new ColorMatrix(new float[][]{
new float[]{0.3086F,0.3086F,0.3086F,0,0},
new float[]{0.6094F,0.6094F,0.6094F,0,0},
new float[]{0.082F,0.082F,0.082F,0,0},
new float[]{0,0,0,1,0,0},
new float[]{0,0,0,0,1,0},
new float[]{0,0,0,0,0,1}}));
// create the grayscale image
g.DrawImage(image, new Rectangle(0, 0, image.Width, image.Height),
0, 0, image.Width, image.Height, GraphicsUnit.Pixel, attr);
// save to the file system
grayImage.Save(grayFilePath, ImageFormat.Jpeg);
// success
MessageBox.Show(string.Format("Copied grayscale image {0}", grayFilePath), Program.KeyName);
}
}
catch (Exception ex)
{
MessageBox.Show(string.Format("An error occurred: {0}", ex.Message), Program.KeyName);
return;
}
}
}
}
UPDATE
This is Program.cs now
using System;
using System.Windows.Forms;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
[assembly: CLSCompliant(true)]
namespace SimpleContextMenu
{
static class Program
{
// file type to register
const string FileType = "bitmapfile";//"jpegfile";
// context menu name in the registry
const string KeyName = "Simple Context Menu";
const string KeyName1 = "Simple Context Menu1";
// context menu text
const string MenuText = "Copy to Grayscale";
const string MenuText1 = "Resize all images";
[STAThread]
static void Main(string[] args)
{
System.Threading.Thread.Sleep(30000);
// process register or unregister commands
if (!ProcessCommand(args))
{
string action = args[0];
MessageBox.Show(action);
string fileName = args[1];
if (action == "Copy")
{
// invoked from shell, process the selected file
CopyGrayscaleImage(fileName);
}
else if (action == "Resize")
{
string FilePath = Path.Combine(
Path.GetDirectoryName(fileName),
string.Format("{0} (resized){1}",
Path.GetFileNameWithoutExtension(fileName),
Path.GetExtension(fileName)));
MessageBox.Show(FilePath);
Bitmap bmp1 = new Bitmap(ResizeImages(FilePath,100,100));
bmp1.Save(FilePath);
bmp1.Dispose();
}
}
}
/// <summary>
/// Process command line actions (register or unregister).
/// </summary>
/// <param name="args">Command line arguments.</param>
/// <returns>True if processed an action in the command line.</returns>
static bool ProcessCommand(string[] args)
{
// register
if (args.Length == 0 || string.Compare(args[0], "-register", true) == 0)
{
// full path to self, %L is placeholder for selected file
string menuCommand = string.Format("\"{0}\" Copy \"%L\"", Application.ExecutablePath);
// register the context menu
FileShellExtension.Register(Program.FileType,
Program.KeyName, Program.MenuText,
menuCommand);
string menuCommand1 = string.Format("\"{0}\" Resize \"%L\"", Application.ExecutablePath);
FileShellExtension.Register(Program.FileType,
Program.KeyName1, Program.MenuText1,
menuCommand1);
MessageBox.Show(string.Format(
"The {0} shell extension was registered.",
Program.KeyName), Program.KeyName);
return true;
}
// unregister
if (string.Compare(args[0], "-unregister", true) == 0)
{
// unregister the context menu
FileShellExtension.Unregister(Program.FileType, Program.KeyName);
MessageBox.Show(string.Format(
"The {0} shell extension was unregistered.",
Program.KeyName), Program.KeyName);
return true;
}
// command line did not contain an action
return false;
}
/// <summary>
/// Make a grayscale copy of the image.
/// </summary>
/// <param name="filePath">Full path to the image to copy.</param>
static void CopyGrayscaleImage(string filePath)
{
try
{
// full path to the grayscale copy
string grayFilePath = Path.Combine(
Path.GetDirectoryName(filePath),
string.Format("{0} (grayscale){1}",
Path.GetFileNameWithoutExtension(filePath),
Path.GetExtension(filePath)));
// using calls Dispose on the objects, important
// so the file is not locked when the app terminates
using (Image image = new Bitmap(filePath))
using (Bitmap grayImage = new Bitmap(image.Width, image.Height))
using (Graphics g = Graphics.FromImage(grayImage))
{
// setup grayscale matrix
ImageAttributes attr = new ImageAttributes();
attr.SetColorMatrix(new ColorMatrix(new float[][]{
new float[]{0.3086F,0.3086F,0.3086F,0,0},
new float[]{0.6094F,0.6094F,0.6094F,0,0},
new float[]{0.082F,0.082F,0.082F,0,0},
new float[]{0,0,0,1,0,0},
new float[]{0,0,0,0,1,0},
new float[]{0,0,0,0,0,1}}));
// create the grayscale image
g.DrawImage(image, new Rectangle(0, 0, image.Width, image.Height),
0, 0, image.Width, image.Height, GraphicsUnit.Pixel, attr);
// save to the file system
grayImage.Save(grayFilePath, ImageFormat.Jpeg);
// success
MessageBox.Show(string.Format("Copied grayscale image {0}", grayFilePath), Program.KeyName);
}
}
catch (Exception ex)
{
MessageBox.Show(string.Format("An error occurred: {0}", ex.Message), Program.KeyName);
return;
}
}
private static Bitmap ResizeImages(String filename, int maxWidth, int maxHeight)
{
using (Image originalImage = Image.FromFile(filename))
{
//Caluate new Size
int newWidth = originalImage.Width;
int newHeight = originalImage.Height;
double aspectRatio = (double)originalImage.Width / (double)originalImage.Height;
if (aspectRatio <= 1 && originalImage.Width > maxWidth)
{
newWidth = maxWidth;
newHeight = (int)Math.Round(newWidth / aspectRatio);
}
else if (aspectRatio > 1 && originalImage.Height > maxHeight)
{
newHeight = maxHeight;
newWidth = (int)Math.Round(newHeight * aspectRatio);
}
if (newWidth >= 0 && newHeight >= 0)
{
Bitmap newImage = new Bitmap(newWidth, newHeight);
using (Graphics g = Graphics.FromImage(newImage))
{
//--Quality Settings Adjust to fit your application
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear;
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
g.DrawImage(originalImage, 0, 0, newImage.Width, newImage.Height);
return newImage;
}
}
return null;
}
}
}
}
For some reason the Resize part is not owrking.
I can't debug it but it should save a resized Bitmap image file on my hard disk but it's not. Can't figure out.
Look at the menuCommand string, the first part should be the path to your program: Application.ExecutablePath, the second part can be the action you specified ("Copy" or "List"), and the third part can be the full path to the selected item, which is represented by the "%L" placeholder.
So the correct way is
string menuCommand = string.Format("\"{0}\" Copy \"%L\"", Application.ExecutablePath);
// register the context menu
FileShellExtension.Register(Program.FileType,
Program.KeyName, Program.MenuText,
menuCommand);
string menuCommand1 = string.Format("\"{0}\" List \"%L\"", Application.ExecutablePath);
// register the context menu 1
FileShellExtension.Register(Program.FileType,
Program.KeyName1, Program.MenuText1,
menuCommand1);
And the Main method
static void Main(string[] args)
{
// process register or unregister commands
if (!ProcessCommand(args))
{
string action = args[0];
MessageBox.Show(action);
string fileName = args[1];
if (action == "Copy")
{
// invoked from shell, process the selected file
CopyGrayscaleImage(fileName);
}
else if (action == "List")
{
ListImage(fileName);
}
}
}
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I can able to get the proper OCR output using newly trained tessedata (version 3.02) through command prompt but I want same output in C# code with DLL ref.I have tried with tessnet2_32.dll reference but It is throwing exception so How to use or access the tesseract 3.02 version trained tessedata using DLL reference through C# code?
To access or use tesseract 3.02 trained data we have to create separate wrapper class like below.
using System;
using System.IO;
using System.Diagnostics;
using System.Drawing;
/// <summary>
/// Summary description for TesseractOCR
/// </summary>
///
namespace tesseractThree
{
public class TesseractOCR
{
public TesseractOCR()
{
//
// TODO: Add constructor logic here
//
}
private string commandpath;
private string outpath;
private string tmppath;
public TesseractOCR(string commandpath)
{
this.commandpath = commandpath;
tmppath = System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + #"\out.tif";
outpath = System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + #"\out.txt";
}
public string analyze(string filename,string lang,bool noLine)
{
string args = filename + " " + outpath.Replace(".txt", "");
ProcessStartInfo startinfo;
if (noLine == true)
{
startinfo = new ProcessStartInfo(commandpath, args + " -l " + lang + " -psm 6");
}
else
{
startinfo = new ProcessStartInfo(commandpath, args + " -l " + lang);
}
startinfo.CreateNoWindow = true;
startinfo.UseShellExecute = false;
Process.Start(startinfo).WaitForExit();
string ret = "";
using (StreamReader r = new StreamReader(outpath))
{
string content = r.ReadToEnd();
ret = content;
}
File.Delete(outpath);
return ret;
}
public string OCRFromBitmap(Bitmap bmp,string lang,bool noLine)
{
bmp.Save(tmppath, System.Drawing.Imaging.ImageFormat.Tiff);
string ret = analyze(tmppath,lang,noLine);
File.Delete(tmppath);
return ret;
}
/* public string OCRFromFile(string filename)
{
return analyze(filename);
}*/
}
}
//Usage of this class
string lang = "enc";
Bitmap b = new Bitmap(#"D:\Image\enc.test_font.exp0.tif");
TesseractOCR ocr = new TesseractOCR(#"C:\Program Files\Tesseract-OCR\tesseract.exe");
string result = ocr.OCRFromBitmap(b, lang,true);
Label1.Text = result;
OR Refer below link for more details.
https://gist.github.com/yatt/915443
That was for Tesseract 2.04. You'll need a .NET wrapper compatible with 3.02 version.
Using the tesseractengine3.dll we can use tesseract v3.02 trained data like below.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using tesseract;
using System.Drawing;
using System.IO;
public enum TesseractEngineMode : int
{
/// <summary>
/// Run Tesseract only - fastest
/// </summary>
TESSERACT_ONLY = 0,
/// <summary>
/// Run Cube only - better accuracy, but slower
/// </summary>
CUBE_ONLY = 1,
/// <summary>
/// Run both and combine results - best accuracy
/// </summary>
TESSERACT_CUBE_COMBINED = 2,
/// <summary>
/// Specify this mode when calling init_*(),
/// to indicate that any of the above modes
/// should be automatically inferred from the
/// variables in the language-specific config,
/// command-line configs, or if not specified
/// in any of the above should be set to the
/// default OEM_TESSERACT_ONLY.
/// </summary>
DEFAULT = 3
}
public enum TesseractPageSegMode : int
{
/// <summary>
/// Fully automatic page segmentation
/// </summary>
PSM_AUTO = 0,
/// <summary>
/// Assume a single column of text of variable sizes
/// </summary>
PSM_SINGLE_COLUMN = 1,
/// <summary>
/// Assume a single uniform block of text (Default)
/// </summary>
PSM_SINGLE_BLOCK = 2,
/// <summary>
/// Treat the image as a single text line
/// </summary>
PSM_SINGLE_LINE = 3,
/// <summary>
/// Treat the image as a single word
/// </summary>
PSM_SINGLE_WORD = 4,
/// <summary>
/// Treat the image as a single character
/// </summary>
PSM_SINGLE_CHAR = 5
}
public partial class importDLL : System.Web.UI.Page
{
private TesseractProcessor m_tesseract = null;
//private const string m_path = #"..\..\data\";
private const string m_path = #"D:\tessdata-3.02\";
private const string m_lang = "eng";
protected void Page_Load(object sender, EventArgs e)
{
var image = System.Drawing.Image.FromFile(#"D:\Image\Capture1T.tif");
m_tesseract = new TesseractProcessor();
bool succeed = m_tesseract.Init(m_path, m_lang, (int)TesseractEngineMode.DEFAULT);
if (!succeed)
{
}
m_tesseract.SetVariable("tessedit_pageseg_mode", ((int)TesseractPageSegMode.PSM_SINGLE_LINE).ToString());
m_tesseract.Clear();
m_tesseract.ClearAdaptiveClassifier();
string outValue= m_tesseract.Apply(image);
Response.Write(outValue);
}
}
I need to create an application that parses a PST file and converts the mails into multiple EML files. Basically, I need to do the opposite of what's being asked in this question.
Is there any sample code or guidelines to achieve this feature?
You could use the Outlook Redemption library which is capable of opening PST and extracting messages as .EML (among other formats). Redemption is a COM Object (32 or 64 bit) that can be used in C# without any problem. Here is a Console Application sample code that demonstrates this:
using System;
using System.IO;
using System.Text;
using Redemption;
namespace DumpPst
{
class Program
{
static void Main(string[] args)
{
// extract 'test.pst' in the 'test' folder
ExtractPst("test.pst", Path.GetFullPath("test"));
}
public static void ExtractPst(string pstFilePath, string folderPath)
{
if (pstFilePath == null)
throw new ArgumentNullException("pstFilePath");
RDOSession session = new RDOSession();
RDOPstStore store = session.LogonPstStore(pstFilePath);
ExtractPstFolder(store.RootFolder, folderPath);
}
public static void ExtractPstFolder(RDOFolder folder, string folderPath)
{
if (folder == null)
throw new ArgumentNullException("folder");
if (folderPath == null)
throw new ArgumentNullException("folderPath");
if (folder.FolderKind == rdoFolderKind.fkSearch)
return;
if (!Directory.Exists(folderPath))
{
Directory.CreateDirectory(folderPath);
}
foreach(RDOFolder child in folder.Folders)
{
ExtractPstFolder(child, Path.Combine(folderPath, ToFileName(child.Name)));
}
foreach (var item in folder.Items)
{
RDOMail mail = item as RDOMail;
if (mail == null)
continue;
mail.SaveAs(Path.Combine(folderPath, ToFileName(mail.Subject)) + ".eml", rdoSaveAsType.olRFC822);
}
}
/// <summary>
/// Converts a text into a valid file name.
/// </summary>
/// <param name="fileName">The file name.</param>
/// <returns>
/// A valid file name.
/// </returns>
public static string ToFileName(string fileName)
{
return ToFileName(fileName, null, null);
}
/// <summary>
/// Converts a text into a valid file name.
/// </summary>
/// <param name="fileName">The file name.</param>
/// <param name="reservedNameFormat">The reserved format to use for reserved names. If null '_{0}_' will be used.</param>
/// <param name="reservedCharFormat">The reserved format to use for reserved characters. If null '_x{0}_' will be used.</param>
/// <returns>
/// A valid file name.
/// </returns>
public static string ToFileName(string fileName, string reservedNameFormat, string reservedCharFormat)
{
if (fileName == null)
throw new ArgumentNullException("fileName");
if (string.IsNullOrEmpty(reservedNameFormat))
{
reservedNameFormat = "_{0}_";
}
if (string.IsNullOrEmpty(reservedCharFormat))
{
reservedCharFormat = "_x{0}_";
}
if (Array.IndexOf(ReservedFileNames, fileName.ToLowerInvariant()) >= 0 ||
IsAllDots(fileName))
return string.Format(reservedNameFormat, fileName);
char[] invalid = Path.GetInvalidFileNameChars();
StringBuilder sb = new StringBuilder(fileName.Length);
foreach (char c in fileName)
{
if (Array.IndexOf(invalid, c) >= 0)
{
sb.AppendFormat(reservedCharFormat, (short)c);
}
else
{
sb.Append(c);
}
}
string s = sb.ToString();
// directory limit is 255
if (s.Length > 254)
{
s = s.Substring(0, 254);
}
if (string.Equals(s, fileName, StringComparison.Ordinal))
{
s = fileName;
}
return s;
}
private static bool IsAllDots(string fileName)
{
foreach (char c in fileName)
{
if (c != '.')
return false;
}
return true;
}
private static readonly string[] ReservedFileNames = new[]
{
"con", "prn", "aux", "nul",
"com0", "com1", "com2", "com3", "com4", "com5", "com6", "com7", "com8", "com9",
"lpt0", "lpt1", "lpt2", "lpt3", "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9"
};
}
}
You need essentially to do the inverse of what is being asked in that question.
Load the PST file using Outlook interop (or redemption as above)
Enumerate all the files.
Use CDO, System.Mail or similar to compose an EML file for each file in the PST.
The thing to note is that a PST doesn't contain EML files, it contains MSG files. So you will have to do some form of conversion, and you will not get back exactly what was originally sent.
See also this question: Are there .NET Framework methods to parse an email (MIME)?
Recently, I decided to play with Windows Presentation Foundation and create a variation of chess. The whole thing is kinda done (I believe) but it's a long time now as I can't find a way to set my PNG file as a Image control. This is exemplary class which is affected by a issue:
public class Field
{
public Image Image { get; set; }
public Image GetImage(String keyName)
{
ResourceDictionary imagesDictionary = new ResourceDictionary();
imagesDictionary.Source = new Uri("file:/[...]/ImagesDictionary.xaml");
var var = imagesDictionary[keyName];
Image image = (Image) imagesDictionary[keyName];
return image;
}
public void RefreshImage()
{
if (Unit.Subclass.CompareTo("Bishop").Equals(0))
{
if (Unit.Player.IsWhite)
{
this.Image = this.GetImage("WhiteBishop");
}
...
}
}
My ImagesDictionary.xaml file:
<ResourceDictionary>
<ImageSource x:Key="BlackBishop">BlackBishop.png</ImageSource>
<ImageSource x:Key="WhiteBishop">WhiteBishop.png</ImageSource>
...
</ResourceDictionary>
And the issue is that I don't know how to convert the output of GetImage
(System.Windows.Media.Imaging.BitmapFrameDecode)
into the
(System.Windows.Controls.Image)
Any ideas?
System.Windows.Media.Imaging.BitmapFrame is derived from ImageSource.
You should be able to do this:
this.Image = new Image();
this.Image.Source = this.GetImage("WhiteBishop");
or
this.Image.Source = this.GetImage("WhiteBishop").Source;
If BitmapFrameDecode is truly derived from System.Windows.Imaging.Image, not from ImageSource.
-Jesse
OK, here is an improved GetImageSource (name changed to reflect its real purpose).
/// <summary>
/// Get an ImageSource from the ResourceDictionary referred to by the
/// <paramref name="uriDictionary"/>.
/// </summary>
/// <param name="keyName">The ResourceDictionary key of the ImageSource
/// to retrieve.</param>
/// <param name="uriDictionary">The Uri to the XAML file that holds
/// the ResourceDictionary.</param>
/// <returns><c>null</c> on failure, the requested <c>ImageSource</c>
/// on success.</returns>
/// <remarks>If the requested resource is an <c>Image</c> instead of
/// an <c>ImageSource</c>,
/// then the <c>image.Source</c> is returned.</remarks>
public static ImageSource GetImageSource(String keyName, Uri uriDictionary)
{
if (String.IsNullOrEmpty(keyName))
throw new ArgumentNullException("keyName");
if (null == uriDictionary)
throw new ArgumentNullException("uriDictionary");
ResourceDictionary imagesDictionary = new ResourceDictionary();
imagesDictionary.Source = uriDictionary;
var var = imagesDictionary[keyName];
Object blob = imagesDictionary[keyName];
Debug.WriteLine(String.Format(
"error: GetImageSource( '{0}', '{1}' )"
+ " value is: {2}",
keyName,
uriDictionary,
(null == blob) ? "null" : blob.GetType().FullName));
if (null != blob)
{
if (blob is ImageSource)
{
return blob as ImageSource;
}
if (blob is Image)
{
Image image = blob as Image;
return image.Source;
}
if (blob is System.Drawing.Image)
{
System.Drawing.Image dImage = blob as System.Drawing.Image;
MemoryStream mem = new MemoryStream();
dImage.Save(mem, System.Drawing.Imaging.ImageFormat.MemoryBmp);
mem.Position = 0;
BitmapDecoder decode = new BmpBitmapDecoder(
mem,
BitmapCreateOptions.None,
BitmapCacheOption.None);
return decode.Frames[0];
}
Debug.WriteLine(String.Format(
"error: GetImageSource( '{0}', '{1}' )"
+ " can't handle type: {2}",
keyName,
uriDictionary,
blob.GetType().FullName));
}
return null;
}
And to use it you would do this:
String packText = String.Format("pack://application:,,,/{0};component/{1}",
Assembly.GetEntryAssembly().FullName,
"ImageDictionary.xaml");
Uri imageUri = new Uri(packText);
// or if you prefer:
// Uri imageUri = new Uri("file:///.../ImageDictionary.xaml");
//
ImageSource source = GetImageSource(imageKey, imageUri);
if (null != source)
{
this.Image.Source = source;
}
else
{
// bail ...
}
The Drawing.Image case will handle BMP, PNG, JPG, GIF, etc., even though I used BmpBitmapDecoder. But be aware that XAML images stretch very prettily but Drawing.Image does not.
-Jesse
Dim img As New BitmapImage
Using mem As New System.IO.MemoryStream(<InputArrayHere>)
img.BeginInit()
img.StreamSource = mem
img.EndInit()
End Using
return img
I spent a lot of time trying to figure out a good way to embed any file into Microsoft Word using OpenXml 2.0; Office documents are fairly easy but what about other file types such as PDF, TXT, GIF, JPG, HTML, etc....
What is a good way to get this to work for any file type, in C#?
Embedding Foreign Objects (PDF, TXT, GIF, etc…) into Microsoft Word using OpenXml 2.0
(Well, in collaboration with COM)
I got a lot from this site, so here I asked and answered my own question in order to give back a little on a topic in which I had difficulty finding answers on, hope it helps people.
There are several examples out there that show how to embed an Office Document into another Office Document using OpenXml 2.0, what’s not out there and easily understandable is how to embed just about any file into and Office Document.
I have learned a lot from other people’s code, so this is my attempt to contribute. Since I am already using OpenXml to generate documents, and I am in need of embedding other files into Word, I have decided use a collaboration of OpenXml and COM (Microsoft Office 2007 dll’s) to achieve my goal. If you are like me, “invoking the OLE server application to create an IStorage” doesn’t mean much to you.
In this example I’d like to show how I use COM to PROGRMATICALLY get the OLE-binary data information of the attached file, and then how I used that information within my OpenXml document. Basically, I am programmatically looking at the OpenXml 2.0 Document Reflector to get the information I need.
My code below is broken down into several classes, but here is an outline of what I am doing:
Create an OpenXml WordProcessingDocument, get the System.IO.FileInfo for the file you want to Embed
Create a custom OpenXmlEmbeddedObject object (this is what holds all the binary data)
Use the binary data from the above step to create Data and Image Streams
Use those Streams as the File Object and File Image for your OpenXml Document
I know there is a lot of code, and not much explanation… Hopefully it is easy to follow and will help people out
Requirements:
• DocumentFormat.OpenXml dll (OpenXml 2.0)
• WindowsBase dll
• Microsoft.Office.Interop.Word dll (Office 2007 – version 12)
• This the main class that starts everything, opens a WordProcessingDocument and class to have the file attached
using DocumentFormat.OpenXml.Packaging;
using System.IO;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Wordprocessing;
public class MyReport
{
private MainDocumentPart _mainDocumentPart;
public void CreateReport()
{
using (WordprocessingDocument wpDocument = WordprocessingDocument.Create(#"TempPath\MyReport.docx", WordprocessingDocumentType.Document))
{
_mainDocumentPart = wpDocument.AddMainDocumentPart();
_mainDocumentPart.Document = new Document(new Body());
AttachFile(#"MyFilePath\MyFile.pdf", true);
}
}
private void AttachFile(string filePathAndName, bool displayAsIcon)
{
FileInfo fileInfo = new FileInfo(filePathAndName);
OpenXmlHelper.AppendEmbeddedObject(_mainDocumentPart, fileInfo, displayAsIcon);
}
}
• This class in an OpenXml helper class, holds all the logic to embed an object into your OpenXml File
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Validation;
using DocumentFormat.OpenXml.Wordprocessing;
using OVML = DocumentFormat.OpenXml.Vml.Office;
using V = DocumentFormat.OpenXml.Vml;
public class OpenXmlHelper
{
/// <summary>
/// Appends an Embedded Object into the specified Main Document
/// </summary>
/// <param name="mainDocumentPart">The MainDocument Part of your OpenXml Word Doc</param>
/// <param name="fileInfo">The FileInfo object associated with the file being embedded</param>
/// <param name="displayAsIcon">Whether or not to display the embedded file as an Icon (Otherwise it will display a snapshot of the file)</param>
public static void AppendEmbeddedObject(MainDocumentPart mainDocumentPart, FileInfo fileInfo, bool displayAsIcon)
{
OpenXmlEmbeddedObject openXmlEmbeddedObject = new OpenXmlEmbeddedObject(fileInfo, displayAsIcon);
if (!String.IsNullOrEmpty(openXmlEmbeddedObject.OleObjectBinaryData))
{
using (Stream dataStream = new MemoryStream(Convert.FromBase64String(openXmlEmbeddedObject.OleObjectBinaryData)))
{
if (!String.IsNullOrEmpty(openXmlEmbeddedObject.OleImageBinaryData))
{
using (Stream emfStream = new MemoryStream(Convert.FromBase64String(openXmlEmbeddedObject.OleImageBinaryData)))
{
string imagePartId = GetUniqueXmlItemID();
ImagePart imagePart = mainDocumentPart.AddImagePart(ImagePartType.Emf, imagePartId);
if (emfStream != null)
{
imagePart.FeedData(emfStream);
}
string embeddedPackagePartId = GetUniqueXmlItemID();
if (dataStream != null)
{
if (openXmlEmbeddedObject.ObjectIsOfficeDocument)
{
EmbeddedPackagePart embeddedObjectPart = mainDocumentPart.AddNewPart<EmbeddedPackagePart>(
openXmlEmbeddedObject.FileContentType, embeddedPackagePartId);
embeddedObjectPart.FeedData(dataStream);
}
else
{
EmbeddedObjectPart embeddedObjectPart = mainDocumentPart.AddNewPart<EmbeddedObjectPart>(
openXmlEmbeddedObject.FileContentType, embeddedPackagePartId);
embeddedObjectPart.FeedData(dataStream);
}
}
if (!displayAsIcon && !openXmlEmbeddedObject.ObjectIsPicture)
{
Paragraph attachmentHeader = CreateParagraph(String.Format("Attachment: {0} (Double-Click to Open)", fileInfo.Name));
mainDocumentPart.Document.Body.Append(attachmentHeader);
}
Paragraph embeddedObjectParagraph = GetEmbeededObjectParagraph(openXmlEmbeddedObject.FileType,
imagePartId, openXmlEmbeddedObject.OleImageStyle, embeddedPackagePartId);
mainDocumentPart.Document.Body.Append(embeddedObjectParagraph);
}
}
}
}
}
/// <summary>
/// Gets Paragraph that includes the embedded object
/// </summary>
private static Paragraph GetEmbeededObjectParagraph(string fileType, string imageID, string imageStyle, string embeddedPackageID)
{
EmbeddedObject embeddedObject = new EmbeddedObject();
string shapeID = GetUniqueXmlItemID();
V.Shape shape = new V.Shape() { Id = shapeID, Style = imageStyle };
V.ImageData imageData = new V.ImageData() { Title = "", RelationshipId = imageID };
shape.Append(imageData);
OVML.OleObject oleObject = new OVML.OleObject()
{
Type = OVML.OleValues.Embed,
ProgId = fileType,
ShapeId = shapeID,
DrawAspect = OVML.OleDrawAspectValues.Icon,
ObjectId = GetUniqueXmlItemID(),
Id = embeddedPackageID
};
embeddedObject.Append(shape);
embeddedObject.Append(oleObject);
Paragraph paragraphImage = new Paragraph();
Run runImage = new Run(embeddedObject);
paragraphImage.Append(runImage);
return paragraphImage;
}
/// <summary>
/// Gets a Unique ID for an XML Item, for reference purposes
/// </summary>
/// <returns>A GUID string with removed dashes</returns>
public static string GetUniqueXmlItemID()
{
return "r" + System.Guid.NewGuid().ToString().Replace("-", "");
}
private static Paragraph CreateParagraph(string paragraphText)
{
Paragraph paragraph = new Paragraph();
ParagraphProperties paragraphProperties = new ParagraphProperties();
paragraphProperties.Append(new Justification()
{
Val = JustificationValues.Left
});
paragraphProperties.Append(new SpacingBetweenLines()
{
After = Convert.ToString(100),
Line = Convert.ToString(100),
LineRule = LineSpacingRuleValues.AtLeast
});
Run run = new Run();
RunProperties runProperties = new RunProperties();
Text text = new Text();
if (!String.IsNullOrEmpty(paragraphText))
{
text.Text = paragraphText;
}
run.Append(runProperties);
run.Append(text);
paragraph.Append(paragraphProperties);
paragraph.Append(run);
return paragraph;
}
}
• This is the most important part of this process, it is using Microsoft's internal OLE Server, creates the Binary DATA and Binary EMF information for a file. All you have to here is call the OpenXmlEmbeddedObject constructor and all get’s taken care of. It will mimic the process that goes on when you manually drag any file into Word; there is some kind of conversion that goes on when you do that, turning the file into an OLE object, so that Microsoft can recognize the file.
o The most imporant parts of this class are the OleObjectBinaryData and OleImageBinaryData properties; they contain the 64Bit string binary info for the file data and ‘.emf’ image.
o If you choose to not display the file as an icon, then the ‘.emf’ image data will create a snapshot of the file, like the first page of the pdf file for example, in which you can still double-click to open
o If you are embedding an image and choose not to display it as an Icon, then the OleObjectBinaryData and OleImageBinaryData properties will be the same
using System.Runtime.InteropServices;
using System.Xml;
using System.Diagnostics;
using System.IO;
using System.Drawing;
using Microsoft.Office.Interop.Word;
public class OpenXmlEmbeddedObject
{
#region Constants
private const string _defaultOleContentType = "application/vnd.openxmlformats-officedocument.oleObject";
private const string _oleObjectDataTag = "application/vnd";
private const string _oleImageDataTag = "image/x-emf";
#endregion Constants
#region Member Variables
private static FileInfo _fileInfo;
private static string _filePathAndName;
private static bool _displayAsIcon;
private static bool _objectIsPicture;
private object _objectMissing = System.Reflection.Missing.Value;
private object _objectFalse = false;
private object _objectTrue = true;
#endregion Member Variables
#region Properties
/// <summary>
/// The File Type, as stored in Registry (Ex: a GIF Image = 'giffile')
/// </summary>
public string FileType
{
get
{
if (String.IsNullOrEmpty(_fileType) && _fileInfo != null)
{
_fileType = GetFileType(_fileInfo, false);
}
return _fileType;
}
}
private string _fileType;
/// <summary>
/// The File Context Type, as storered in Registry (Ex: a GIF Image = 'image/gif')
/// * Is converted into the 'Default Office Context Type' for non-office files
/// </summary>
public string FileContentType
{
get
{
if (String.IsNullOrEmpty(_fileContentType) && _fileInfo != null)
{
_fileContentType = GetFileContentType(_fileInfo);
if (!_fileContentType.Contains("officedocument"))
{
_fileContentType = _defaultOleContentType;
}
}
return _fileContentType;
}
}
private string _fileContentType;
/// <summary>
/// Gets the ContentType Text for the file
/// </summary>
public static string GetFileContentType(FileInfo fileInfo)
{
if (fileInfo == null)
{
throw new ArgumentNullException("fileInfo");
}
string mime = "application/octetstream";
string ext = System.IO.Path.GetExtension(fileInfo.Name).ToLower();
Microsoft.Win32.RegistryKey rk = Microsoft.Win32.Registry.ClassesRoot.OpenSubKey(ext);
if (rk != null && rk.GetValue("Content Type") != null)
{
mime = rk.GetValue("Content Type").ToString();
}
return mime;
}
public bool ObjectIsOfficeDocument
{
get { return FileContentType != _defaultOleContentType; }
}
public bool ObjectIsPicture
{
get { return _objectIsPicture; }
}
public string OleObjectBinaryData
{
get { return _oleObjectBinaryData; }
set { _oleObjectBinaryData = value; }
}
private string _oleObjectBinaryData;
public string OleImageBinaryData
{
get { return _oleImageBinaryData; }
set { _oleImageBinaryData = value; }
}
private string _oleImageBinaryData;
/// <summary>
/// The OpenXml information for the Word Application that is created (Make-Shoft Code Reflector)
/// </summary>
public string WordOpenXml
{
get { return _wordOpenXml; }
set { _wordOpenXml = value; }
}
private String _wordOpenXml;
/// <summary>
/// The XmlDocument that is created based on the OpenXml Data from WordOpenXml
/// </summary>
public XmlDocument OpenXmlDocument
{
get
{
if (_openXmlDocument == null && !String.IsNullOrEmpty(WordOpenXml))
{
_openXmlDocument = new XmlDocument();
_openXmlDocument.LoadXml(WordOpenXml);
}
return _openXmlDocument;
}
}
private XmlDocument _openXmlDocument;
/// <summary>
/// The XmlNodeList, for all Nodes containing 'binaryData'
/// </summary>
public XmlNodeList BinaryDataXmlNodesList
{
get
{
if (_binaryDataXmlNodesList == null && OpenXmlDocument != null)
{
_binaryDataXmlNodesList = OpenXmlDocument.GetElementsByTagName("pkg:binaryData");
}
return _binaryDataXmlNodesList;
}
}
private XmlNodeList _binaryDataXmlNodesList;
/// <summary>
/// Icon Object for the file
/// </summary>
public Icon ObjectIcon
{
get
{
if (_objectIcon == null)
{
_objectIcon = Enterprise.Windows.Win32.Win32.GetLargeIcon(_filePathAndName);
}
return _objectIcon;
}
}
private Icon _objectIcon;
/// <summary>
/// File Name for the Icon being created
/// </summary>
public string ObjectIconFile
{
get
{
if (String.IsNullOrEmpty(_objectIconFile))
{
_objectIconFile = String.Format("{0}.ico", _filePathAndName.Replace(".", ""));
}
return _objectIconFile;
}
}
private string _objectIconFile;
/// <summary>
/// Gets the original height and width of the emf file being created
/// </summary>
public string OleImageStyle
{
get
{
if (String.IsNullOrEmpty(_oleImageStyle) && !String.IsNullOrEmpty(WordOpenXml))
{
XmlNodeList xmlNodeList = OpenXmlDocument.GetElementsByTagName("v:shape");
if (xmlNodeList != null && xmlNodeList.Count > 0)
{
foreach (XmlAttribute attribute in xmlNodeList[0].Attributes)
{
if (attribute.Name == "style")
{
_oleImageStyle = attribute.Value;
}
}
}
}
return _oleImageStyle;
}
set { _oleImageStyle = value; }
}
private string _oleImageStyle;
#endregion Properties
#region Constructor
/// <summary>
/// Generates binary information for the file being passed in
/// </summary>
/// <param name="fileInfo">The FileInfo object for the file to be embedded</param>
/// <param name="displayAsIcon">Whether or not to display the file as an Icon (Otherwise it will show a snapshot view of the file)</param>
public OpenXmlEmbeddedObject(FileInfo fileInfo, bool displayAsIcon)
{
_fileInfo = fileInfo;
_filePathAndName = fileInfo.ToString();
_displayAsIcon = displayAsIcon;
SetupOleFileInformation();
}
#endregion Constructor
#region Methods
/// <summary>
/// Creates a temporary Word App in order to add an OLE Object, get's the OpenXML data from the file (similar to the Code Reflector info)
/// </summary>
private void SetupOleFileInformation()
{
Microsoft.Office.Interop.Word.Application wordApplication = new Microsoft.Office.Interop.Word.Application();
Microsoft.Office.Interop.Word.Document wordDocument = wordApplication.Documents.Add(ref _objectMissing, ref _objectMissing,
ref _objectMissing, ref _objectMissing);
object iconObjectFileName = _objectMissing;
object objectClassType = FileType;
object objectFilename = _fileInfo.ToString();
Microsoft.Office.Interop.Word.InlineShape inlineShape = null;
if (_displayAsIcon)
{
if (ObjectIcon != null)
{
using (FileStream iconStream = new FileStream(ObjectIconFile, FileMode.Create))
{
ObjectIcon.Save(iconStream);
iconObjectFileName = ObjectIconFile;
}
}
object objectIconLabel = _fileInfo.Name;
inlineShape = wordDocument.InlineShapes.AddOLEObject(ref objectClassType,
ref objectFilename, ref _objectFalse, ref _objectTrue, ref iconObjectFileName,
ref _objectMissing, ref objectIconLabel, ref _objectMissing);
}
else
{
try
{
Image image = Image.FromFile(_fileInfo.ToString());
_objectIsPicture = true;
OleImageStyle = String.Format("height:{0}pt;width:{1}pt", image.Height, image.Width);
wordDocument.InlineShapes.AddPicture(_fileInfo.ToString(), ref _objectMissing, ref _objectTrue, ref _objectMissing);
}
catch
{
inlineShape = wordDocument.InlineShapes.AddOLEObject(ref objectClassType,
ref objectFilename, ref _objectFalse, ref _objectFalse, ref _objectMissing, ref _objectMissing,
ref _objectMissing, ref _objectMissing);
}
}
WordOpenXml = wordDocument.Range(ref _objectMissing, ref _objectMissing).WordOpenXML;
if (_objectIsPicture)
{
OleObjectBinaryData = GetPictureBinaryData();
OleImageBinaryData = GetPictureBinaryData();
}
else
{
OleObjectBinaryData = GetOleBinaryData(_oleObjectDataTag);
OleImageBinaryData = GetOleBinaryData(_oleImageDataTag);
}
// Not sure why, but Excel seems to hang in the processes if you attach an Excel file…
// This kills the excel process that has been started < 15 seconds ago (so not to kill the user's other Excel processes that may be open)
if (FileType.StartsWith("Excel"))
{
Process[] processes = Process.GetProcessesByName("EXCEL");
foreach (Process process in processes)
{
if (DateTime.Now.Subtract(process.StartTime).Seconds <= 15)
{
process.Kill();
break;
}
}
}
wordDocument.Close(ref _objectFalse, ref _objectMissing, ref _objectMissing);
wordApplication.Quit(ref _objectMissing, ref _objectMissing, ref _objectMissing);
}
/// <summary>
/// Gets the binary data from the Xml File that is associated with the Tag passed in
/// </summary>
/// <param name="binaryDataXmlTag">the Tag to look for in the OpenXml</param>
/// <returns></returns>
private string GetOleBinaryData(string binaryDataXmlTag)
{
string binaryData = null;
if (BinaryDataXmlNodesList != null)
{
foreach (XmlNode xmlNode in BinaryDataXmlNodesList)
{
if (xmlNode.ParentNode != null)
{
foreach (XmlAttribute attr in xmlNode.ParentNode.Attributes)
{
if (String.IsNullOrEmpty(binaryData) && attr.Value.Contains(binaryDataXmlTag))
{
binaryData = xmlNode.InnerText;
break;
}
}
}
}
}
return binaryData;
}
/// <summary>
/// Gets the image Binary data, if the file is an image
/// </summary>
/// <returns></returns>
private string GetPictureBinaryData()
{
string binaryData = null;
if (BinaryDataXmlNodesList != null)
{
foreach (XmlNode xmlNode in BinaryDataXmlNodesList)
{
binaryData = xmlNode.InnerText;
break;
}
}
return binaryData;
}
/// <summary>
/// Gets the file type description ("Application", "Text Document", etc.) for the file.
/// </summary>
/// <param name="fileInfo">FileInfo containing extention</param>
/// <returns>Type Description</returns>
public static string GetFileType(FileInfo fileInfo, bool returnDescription)
{
if (fileInfo == null)
{
throw new ArgumentNullException("fileInfo");
}
string description = "File";
if (string.IsNullOrEmpty(fileInfo.Extension))
{
return description;
}
description = string.Format("{0} File", fileInfo.Extension.Substring(1).ToUpper());
RegistryKey typeKey = Registry.ClassesRoot.OpenSubKey(fileInfo.Extension);
if (typeKey == null)
{
return description;
}
string type = Convert.ToString(typeKey.GetValue(string.Empty));
RegistryKey key = Registry.ClassesRoot.OpenSubKey(type);
if (key == null)
{
return description;
}
if (returnDescription)
{
description = Convert.ToString(key.GetValue(string.Empty));
return description;
}
else
{
return type;
}
}
#endregion Methods
}
_objectIcon = Enterprise.Windows.Win32.Win32.GetLargeIcon(_filePathAndName);
seems to be broken, but
_objectIcon = System.Drawing.Icon.ExtractAssociatedIcon(_filePathAndName);
should also work.
My answer here will tell you how to do this, but not show you with the SDK or a specific language.
This is a great answer and it helped me a lot, but the potential bug that user bic mentioned also exists
in
OpenXmlEmbeddedObject(FileInfo fileInfo, bool displayAsIcon)
at line 242,
_filePathAndName = fileInfo.ToString();
in
SetupOleFileInformation()
at line 264,
object objectFilename = _fileInfo.ToString();
line 289, and
Image image = Image.FromFile(_fileInfo.ToString());
line 293
wordDocument.InlineShapes.AddPicture(_fileInfo.toString(), ref _objectMissing, ref _objectTrue, ref _objectMissing);
All of these need to be "FullName" instead of "ToString()" if the code should work with relative paths as well. Hope this helps anyone who wants to use D Lyonnais's code!
Make a copy of the document how you wanted to get through code and then use Open XML SDK Tool 2.5 for Microsoft Office for writing code. This tool reflects code. which you can simply copy paste.