WPF Canvas to word documents using OpenXML - wpf

I'm currently working on a project that requires importing the image drawn on a WPF Canvas (Mostly Geometries like lines and ellipses inside Path) into a Word Document. I'm using Openxml to do the job. Here's what I did
I convert read the content of the Canvas into a memory stream
I used the guide provided my Microsoft on how to insert image into Word files How to: Insert a picture into a word processing document (Open XML SDK)
Here's what I've got so far,
Canvas is converted into memory stream by the following piece of code
public static Stream CreateJPGStream(this Canvas canvas)
{
RenderTargetBitmap renderBitmap = new RenderTargetBitmap((int)canvas.ActualWidth, (int)canvas.ActualHeight, 96d, 96d, PixelFormats.Pbgra32);
canvas.Measure(new Size((int)canvas.ActualWidth, (int)canvas.ActualHeight));
canvas.Arrange(new Rect(new Size((int)canvas.ActualWidth, (int)canvas.ActualHeight)));
renderBitmap.Render(canvas);
var stream = new MemoryStream();
var encoder = new JpgBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(renderBitmap));
encoder.Save(stream);
return stream;
}
I believe this was not the cause of the problem since I have been using this code for a while now and I haven't had any issues so far
Then I just modified code from Microsoft Guide
public static void InsertPicture(this WordprocessingDocument word, Stream stream)
{
MainDocumentPart mainPart = word.MainDocumentPart;
if (mainPart == null)
{
mainPart = word.AddMainDocumentPart();
mainPart.Document = new Document() { Body = new Body() };
}
ImagePart imagePart = mainPart.AddImagePart(ImagePartType.Jpeg);
imagePart.FeedData(stream);
AddImageToBody(word, mainPart.GetIdOfPart(imagePart));
}
private static void AddImageToBody(WordprocessingDocument wordDoc, string relationshipId)
{
var element =
new Drawing(
new DW.Inline(
new DW.Extent() { Cx = 990000L, Cy = 792000L },
new DW.EffectExtent()
{
LeftEdge = 0L,
TopEdge = 0L,
RightEdge = 0L,
BottomEdge = 0L
},
new DW.DocProperties()
{
Id = 1U,
Name = "Picture 1"
},
new DW.NonVisualGraphicFrameDrawingProperties(
new A.GraphicFrameLocks() { NoChangeAspect = true }),
new A.Graphic(
new A.GraphicData(
new PIC.Picture(
new PIC.NonVisualPictureProperties(
new PIC.NonVisualDrawingProperties()
{
Id = (UInt32Value)0U,
Name = "New Bitmap Image.jpg"
},
new PIC.NonVisualPictureDrawingProperties()),
new PIC.BlipFill(
new A.Blip(
new A.BlipExtensionList(
new A.BlipExtension()
{
Uri =
"{28A0092B-C50C-407E-A947-70E740481C1C}"
})
)
{
Embed = relationshipId,
CompressionState =
A.BlipCompressionValues.Print
},
new A.Stretch(
new A.FillRectangle())),
new PIC.ShapeProperties(
new A.Transform2D(
new A.Offset() { X = 0L, Y = 0L },
new A.Extents() { Cx = 990000L, Cy = 792000L }),
new A.PresetGeometry(
new A.AdjustValueList()
)
{ Preset = A.ShapeTypeValues.Rectangle }))
)
{ Uri = "http://schemas.openxmlformats.org/drawingml/2006/picture" })
)
{
DistanceFromTop = 0U,
DistanceFromBottom = 0U,
DistanceFromLeft = 0U,
DistanceFromRight = 0U,
EditId = "50D07946"
});
wordDoc.MainDocumentPart.Document.Body.AppendChild(new Paragraph(new Run(element)));
}
Now to join this two methods together
public void InsertPicture(Canvas c)
{
using (var word = OpenXmlHelper.Create(filePath))
{
var stream = c.CreateJPGStream();
word.InsertPicture(stream);
}
}
But when I open the document, I get this
Am I doing something wrong with the memorysteam or on the openxml side? Can someone enlighten me please.
PS: I have looked at similar questions already like Inserting Image into DocX using OpenXML and setting the size

After writing to a stream, the stream's position will be at the end of the stream. You must rewind the stream to the beginning before you read from it.
stream.Position = 0;
or
stream.Seek(0, System.IO.SeekOrigin.Begin);

Related

MemoryStream throws System.ObjectDisposedException

I want to resize images for iOS so that I don't have to do it manually all the time. This should be done using WPF but it throws a ObjectDisposedException.
What it does is the user selects a csproj file and then an image which will be resized in 3 sizes. After resizing the file should be safed to disk but it throws an exception.
retrieving the bytes of the original BitmapImage
byte[] data = original.GetByteArray();
The used method:
public static byte[] GetByteArray(this BitmapImage bmi)
{
byte[] data;
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bmi));
using (Sys.MemoryStream ms = new Sys.MemoryStream())
{
encoder.Save(ms);
data = ms.ToArray();
}
return data;
}
the resizing:
private BitmapImage ResizeImage(byte[] imageData, double dheight, double dwidth)
{
int height = (int)dheight;
int width = (int)dwidth;
BitmapImage resizedImage = new BitmapImage();
using (Sys.MemoryStream ms = new Sys.MemoryStream(imageData))
{
resizedImage.CreateOptions = BitmapCreateOptions.IgnoreColorProfile;
resizedImage.CacheOption = BitmapCacheOption.OnLoad;
resizedImage.DecodePixelHeight = height;
resizedImage.DecodePixelWidth = width;
resizedImage.BeginInit(); // Needed only so we can call EndInit()
resizedImage.StreamSource = ms;
resizedImage.EndInit();// This does the actual loading and resizing
}
return resizedImage;
}
then the saving of the files:
public static void Save(this BitmapImage image, string filePath)
{
//PngBitmapEncoder encoder = new PngBitmapEncoder();
//encoder.Frames.Add(BitmapFrame.Create(image));
//using (var fileStream = new System.IO.FileStream(filePath, System.IO.FileMode.Create))
//{
// encoder.Save(fileStream);
//}
File.WriteAllBytes(filePath, image.GetByteArray());
}
how I used it:
var bmi512 = ResizeImage(data, 512, 512);
var bmi256 = ResizeImage(data, 256, 256);
var bmi128 = ResizeImage(data, 128, 128);
bmi512.Save(Sys.Path.Combine(imageFolderPath, String.Format("{0}512{1}", imageName, imageExt)));
bmi256.Save(Sys.Path.Combine(imageFolderPath, String.Format("{0}256{1}", imageName, imageExt)));
bmi128.Save(Sys.Path.Combine(imageFolderPath, String.Format("{0}128{1}", imageName, imageExt)));
it works for retrieving the byte[] of the original but when it try it for bmi512 I get the exception.
Thanks in advance
You have to call BeginInit before you set any of the BitmapImage's properties:
using (var ms = new MemoryStream(imageData))
{
resizedImage.BeginInit();
resizedImage.CreateOptions = BitmapCreateOptions.IgnoreColorProfile;
resizedImage.CacheOption = BitmapCacheOption.OnLoad;
resizedImage.DecodePixelHeight = height;
resizedImage.DecodePixelWidth = width;
resizedImage.StreamSource = ms;
resizedImage.EndInit();
}

iTextSharp image stretching not proportional

I am using Telerik RadRadialGauge and I need to export it to pdf like a picture.
On my GUI the control looks normal
When I try to export it to pdf it is resized not proportionally.
All other elements look good.
using (var ms = new MemoryStream())
{
var document = new Document(PageSize.LETTER, 0, 0, 0, 0);
PdfWriter.GetInstance(document, new FileStream(pdfFile, FileMode.Create));
PdfWriter.GetInstance(document, ms).SetFullCompression();
document.Open();
FileStream fs = new FileStream(imageFile1, FileMode.Open);
var image = iTextSharp.text.Image.GetInstance(fs);
image.ScalePercent(80);
// image.ScaleToFit(document.PageSize.Width , document.PageSize.Height);
// image.ScaleAbsolute(document.PageSize.Width , document.PageSize.Height));
document.Add(image);
}
Here the code to save all the data from GUI as png file.
private void SaveAsPng(RenderTargetBitmap src, string targetFile)
{
try
{
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(src));
using (var stm = File.Create(targetFile))
{
encoder.Save(stm);
}
}
catch (Exception)
{
... }
}

Windows Phone 8.1 Silverlight Secondary Tile isostore error

I'm trying to render a UserControl as an image, and then assign it to a secondary tile and pin it. The resulting URI is
isostore:/Shared/ShellContent/CustomTile.jpg
However, I get the following error:
ExceptionObject = {System.ArgumentException: Value does not fall within the expected range.
at
Windows.UI.StartScreen.SecondaryTileVisualElements.put_Square150x150Logo(Uri value)
at NestWP.ActionTiles.d__1.MoveNext()
I have this piece of code
var customTile = new ActionTileControl();
customTile.Measure(new Size(150, 150));
customTile.Arrange(new Rect(0, 0, 150, 150));
var bmp = new WriteableBitmap(150, 150);
bmp.Render(customTile, null);
bmp.Invalidate();
const string filename = "/Shared/ShellContent/CustomTile.jpg";
using (var isf = IsolatedStorageFile.GetUserStoreForApplication())
{
if (!isf.DirectoryExists("/CustomLiveTiles"))
{
isf.CreateDirectory("/CustomLiveTiles");
}
using (var stream = isf.OpenFile(filename, System.IO.FileMode.OpenOrCreate))
{
bmp.SaveJpeg(stream, 336, 366, 0, 100);
stream.Close();
}
bool ex = isf.FileExists(filename);
ex = ex;
}
string urilink = "isostore:" + filename;
SecondaryTile secondaryTile = new SecondaryTile()
{
TileId = "tileid",
DisplayName = "title",
Arguments = "args"
};
//Error on the line below
secondaryTile.VisualElements.Square150x150Logo = new Uri(urilink, UriKind.Absolute);
secondaryTile.VisualElements.ShowNameOnSquare150x150Logo = false;
bool isPinned = await secondaryTile.RequestCreateAsync();
I checked FileExists and the bool returns true.
How can I get the image to be set as secondary tile?
Hi maybe this source will help you
http://www.windowsapptutorials.com/windows-phone/how-to-create-secondary-tiles-on-windows-phone-start-screen-using-c/

how to map StreamResourceinfo to a absolute URL

I am using the below snipped to save an audio file in the isolated storage. but the exception occurs when streamresourceinfo mapped to a absoluteUri. The uri accepts only the relative uri. Please guide me how to save the audio file using absolute Uri.
private void SaveMp3()
{
string FileName = "Audios/Deer short.mp3";
FileName = "http://www.ugunaflutes.co.uk/Deer short.mp3";
StreamResourceInfo streamResourceInfo = Application.GetResourceStream(new Uri(FileName, UriKind.RelativeOrAbsolute));
using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
if (myIsolatedStorage.FileExists(FileName))
{
myIsolatedStorage.DeleteFile(FileName);
}
using (IsolatedStorageFileStream fileStream = new IsolatedStorageFileStream("Audio.png", FileMode.Create, myIsolatedStorage))
{
using (BinaryWriter writer = new BinaryWriter(fileStream))
{
Stream resourceStream = streamResourceInfo.Stream;
long length = resourceStream.Length;
byte[] buffer = new byte[32];
int readCount = 0;
using (BinaryReader reader = new BinaryReader(streamResourceInfo.Stream))
{
// read file in chunks in order to reduce memory consumption and increase performance
while (readCount < length)
{
int actual = reader.Read(buffer, 0, buffer.Length);
readCount += actual;
writer.Write(buffer, 0, actual);
}
}
}
}
}
}
Thanks in advance.
You can't use Application.GetResourceStream to load an external resource, because URI must to be relative to the application package http://msdn.microsoft.com/en-us/library/ms596994(v=vs.95).aspx.
You need to use WebClient.OpenReadAsync to download your mp3 file and after save it locally to IsolatedStorage, peace of example:
var webClient = new WebClient();
webClient.OpenReadCompleted += (sender, args) =>
{
if (args.Error != null)
{
//save file here
}
};
webClient.OpenReadAsync(new Uri("http://www.ugunaflutes.co.uk/Deer short.mp3"));

Save content of a visual Object as a image file in WPF?

I need to save the content of a WPF Object as an Image file. In my application I have a chart drawn on a Canvas object. This is what I need to save. The Canvas with all child objects.
What you're looking for is the RenderTargetBitmap class. There's an example of its use on the MSDN page I linked, and there's another good example that includes saving to a file here:
RenderTargetBitmap by Eric Sinc
Here is the func which creates RenderTargetBitmap object, that will be used in further funcs.
public static RenderTargetBitmap ConvertToBitmap(UIElement uiElement, double resolution)
{
var scale = resolution / 96d;
uiElement.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));
var sz = uiElement.DesiredSize;
var rect = new Rect(sz);
uiElement.Arrange(rect);
var bmp = new RenderTargetBitmap((int)(scale * (rect.Width)), (int)(scale * (rect.Height)), scale * 96, scale * 96, PixelFormats.Default);
bmp.Render(uiElement);
return bmp;
}
This functionc creates JPEG string content of file and writes it to a file:
public static void ConvertToJpeg(UIElement uiElement, string path, double resolution)
{
var jpegString = CreateJpeg(ConvertToBitmap(uiElement, resolution));
if (path != null)
{
try
{
using (var fileStream = File.Create(path))
{
using (var streamWriter = new StreamWriter(fileStream, Encoding.Default))
{
streamWriter.Write(jpegString);
streamWriter.Close();
}
fileStream.Close();
}
}
catch (Exception ex)
{
//TODO: handle exception here
}
}
}
This function used above to create JPEG string representation of Image content:
public static string CreateJpeg(RenderTargetBitmap bitmap)
{
var jpeg = new JpegBitmapEncoder();
jpeg.Frames.Add(BitmapFrame.Create(bitmap));
string result;
using (var memoryStream = new MemoryStream())
{
jpeg.Save(memoryStream);
memoryStream.Seek(0, SeekOrigin.Begin);
using (var streamReader = new StreamReader(memoryStream, Encoding.Default))
{
result = streamReader.ReadToEnd();
streamReader.Close();
}
memoryStream.Close();
}
return result;
}
Hope this helps.
With the help of the Eric Sinc tutorial I came to the following solution:
It uses a win32 SaveDialog to choose where the file should go and a PngBitmapEncoder (many other BitmapEncoders available!) to convert it to something we can save.
Note that the element being saved in this example is "cnvClasses" and that the size of the output is, quite deliberately, the same as the control.
SaveFileDialog svDlg = new SaveFileDialog();
svDlg.Filter = "PNG files|*.png|All Files|*.*";
svDlg.Title = "Save diagram as PNG";
if (svDlg.ShowDialog().Value == true)
{
RenderTargetBitmap render = new RenderTargetBitmap((int)this.cnvClasses.ActualWidth, (int)this.cnvClasses.ActualHeight, 96, 96, PixelFormats.Pbgra32);
render.Render(cnvClasses);
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(render));
using (FileStream fs = new FileStream(svDlg.FileName, FileMode.Create))
encoder.Save(fs);
}

Resources