I have the following function to get BitmapImage of file.
public static BitmapImage GetThumbnail(string filePath)
{
ShellFile shellFile = ShellFile.FromFilePath(filePath);
BitmapSource shellThumb = shellFile.Thumbnail.ExtraLargeBitmapSource;
BitmapImage bImg = new BitmapImage();
PngBitmapEncoder encoder = new PngBitmapEncoder();
MemoryStream memoryStream = new MemoryStream();
encoder.Frames.Add(BitmapFrame.Create(shellThumb));
encoder.Save(memoryStream);
bImg.BeginInit();
bImg.StreamSource = memoryStream;
bImg.EndInit();
return bImg;
}
When I get Video's Thumbnail it always works.
When I get Presentation (pptx) Thumbnail it doesn't work properly (I have no idea when it does and when it doesn't).
For example, I have 2 files in directory:
And this is how it looks in my program - 1 is ok and 1 isn't (sometimes both are ok, and sometimes both aren't):
I would appreciate if you could tell me what's the problem or maybe give me another way of getting the Thumbnail that will not fail...
p.s.
I would like to remind that with video files it works 100% fine (.mp3, .mp4, .wmv - thats what I tested)
Since I wanted to get pptx thumbnail, I came up with the following solution:
1. I extracted the thumbnail using DotNetZip
2. I got the thumbnail which is located in docProps directory
3. I extracted the thumbnail to memoryStream
4. I converted the memoryStream to BitmapImage and returned it.
here's the code:
public static BitmapImage GetPPTXThumbnail(string filePath)
{
using (ZipFile zip = ZipFile.Read(filePath))
{
ZipEntry e = zip["docProps/thumbnail.jpeg"];
BitmapImage bImg = new BitmapImage();
MemoryStream memoryStream = new MemoryStream();
bImg.BeginInit();
e.Extract(memoryStream);
memoryStream.Seek(0, SeekOrigin.Begin);
bImg.StreamSource = memoryStream;
bImg.EndInit();
return bImg;
}
}
Cant fail with this solution, this solution is only to get PPTX Thumbnail, I assume it works with all office xml files such as docx, xlsx, etc...
Related
I have a web app that runs on Azure. The user can upload an image and I save that image for them. Now when I receive the image, I have it as byte[]. I would like to save it as JPG to save space. The source image could be anything such as PNG, BMP or JPG.
Is it possible to do so? This needs to run on Azure and I am using WebApps/MVC5/C#.
Thanks for any help.
Get the memorystream and then use System.Drawing
var stream = new MemoryStream(byteArray)
Image img = new Bitmap(stream);
img.Save(#"c:\s\pic.png", System.Drawing.Imaging.ImageFormat.Png);
The last line there where you save the file, you can select the format.
So the answers by #mjwills and Cody was correct. I still thought to put the two methods I exactly needed:
public static Image BitmapToBytes(byte[] image, ImageFormat pFormat)
{
var imageObject = new Bitmap(new MemoryStream(image));
var stream = new MemoryStream();
imageObject.Save(stream, pFormat);
return new Bitmap(stream);
}
Also:
public static byte[] ImgToByteArray(Image img)
{
using (MemoryStream mStream = new MemoryStream())
{
img.Save(mStream, img.RawFormat);
return mStream.ToArray();
}
}
Cheers everyone.
I have a wcf service which returns a bmp in byte[]. However Silverlight's Image control doesnt support displaying bmp's so i need to convert the bmp byte[] to png or jpg byte[]. Is there a library out there which does this conversion? Or any other way of displaying the bmp byte[] on the silverlight client?
Thanks!
Update1
In order to achieve the conversion I would have done something like this in .NET
private byte[] ConvertBmpToJpeg(byte[] bmp)
{
using (System.Drawing.Image image = System.Drawing.Image.FromStream(new MemoryStream(bmp)))
{
MemoryStream ms = new MemoryStream();
image.Save(ms, ImageFormat.Jpeg);
return ms.ToArray();
}
}
Since System.Drawing is not available in Silverlight, how do I achieve what the code does above in Silverlight?
Answer
using the library mentioned by dj kraze below-
ExtendedImage img = new ExtendedImage();
var bd = new BmpDecoder();
var je = new JpegEncoder();
bd.Decode(img, new MemoryStream(bitmapBytes));
MemoryStream ms = new MemoryStream();
je.Encode(img, ms);
BitmapImage bi = new BitmapImage();
bi.SetSource(new MemoryStream(ms.ToArray()));
display_ScreenShot.Source = bi;
Here is an even easier way of doing it..
This site may help out a lot
Image Converting
I have found how to do this in .NET 4.0, but I think JpegBitmapEncoder doesn't exist in Silverlight:
MemoryStream memStream = new MemoryStream();
JpegBitmapEncoder encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(imageC));
encoder.Save(memStream);
var bytes = memStream.GetBuffer();
How can I convert an image to bytes[] in silverlight?
UPDATE:
I have a Contact model, which has a Photo property. Whenever I add a new Contact, I would like to load a local default Image and convert it and set the Photo property to it.
var bitmapImage = new BitmapImage
{
UriSource = new Uri("pack://application:,,,/xxx;component/Images/default.JPG")
};
var image = new Image{Source = bitmapImage};
Is this the correct way to load an image in first place?
Use
myImage.Save(memStream, ImageFormat.Jpeg);
return memStream.ToArray();
UPDATE
OK it turns out that the image is a BitmapImage.
It seems that BitmapImage does not expose the functionality to save the image. The solution is to get the image from the embedded resource:
Stream s = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourcePath);
byte[] buffer = new byte[s.Length];
s.Read(buffer, 0, buffer.Length);
Have a look at this library: Imagetools
It contains some nice utilities and jpg and png encoders,
The System.Drawing.Image has the easy to use methods for FromFile and ToFile. What is the equivalent for the Silverlight BitmapImage? I am trying to load and save a jpeg image as part of a unit test. The bytes must match exactly for it to pass. Here is my current guess:
//I am not sure this is right
private BitmapImage GetImage(string fileName)
{
BitmapImage bitmapImage = new System.Windows.Media.Imaging.BitmapImage();
using (Stream imageStreamSource = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
{
bitmapImage.BeginInit();
bitmapImage.StreamSource = imageStreamSource;
bitmapImage.EndInit();
}
return bitmapImage;
}
private void SaveImage(BitmapImage bitmapImage, string file)
{
//How to do this?
}
An in-browser Silverlight application cannot open a file using a filename. You would need it run out-of-browser with elevated trust to do that.
Silverlight has no built-in image encoding so you can't take the contents of a bitmap (BTW you would need to be using WriteableBitmap to be able to access the raw image).
You find something you need in Image Tools.
From MSDN link, use the ctor overload which takes in a URI or
BitmapImage myBitmapImage = new BitmapImage();
// BitmapImage.UriSource must be in a BeginInit/EndInit block
myBitmapImage.BeginInit();
myBitmapImage.UriSource = new Uri(#"C:\Documents and Settings\All Users\Documents\My Pictures\Sample Pictures\Water Lilies.jpg");
myBitmapImage.DecodePixelWidth = 200;
myBitmapImage.EndInit();
//set image source
myImage.Source = myBitmapImage;
To save the image to disk, you'd need the specific encoder e.g. JpegBitmapEncoder
When I try to save a BitmapSource that I loaded earlier, a System.IO.IOException is thrown stating another process is accessing that file and the filestream cannot be opened.
If I only save whithout loading earlier, everything works fine.
The loading code:
BitmapImage image = new BitmapImage();
image.BeginInit();
image.UriSource = uri;
if (decodePixelWidth > 0)
image.DecodePixelWidth = decodePixelWidth;
image.EndInit();
the saving code:
using (FileStream fileStream = new FileStream(Directory + "\\" + FileName + ".jpg", FileMode.Create))
{
JpegBitmapEncoder encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create((BitmapImage)image));
encoder.QualityLevel = 100;
encoder.Save(fileStream);
}
It seems like after loading the image data, the file is still locked an can never be overwritten while the application who opened it is still running. Any ideas how to solve this? Thanks alot for any solutions.
Inspired by the comments I got on this issue, I solved the problem by reading all bytes into a memorystream and using it as the BitmapImage's Sreamsource.
This one works perfectly:
if (File.Exists(filePath))
{
MemoryStream memoryStream = new MemoryStream();
byte[] fileBytes = File.ReadAllBytes(filePath);
memoryStream.Write(fileBytes, 0, fileBytes.Length);
memoryStream.Position = 0;
image.BeginInit();
image.StreamSource = memoryStream;
if (decodePixelWidth > 0)
image.DecodePixelWidth = decodePixelWidth;
image.EndInit();
}
Here is another solution, based upon the original loading code:
var image = new BitmapImage();
image.BeginInit();
// overwrite cache if already exists, to refresh image
image.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
// load into memory and unlock file
image.CacheOption = BitmapCacheOption.OnLoad;
image.UriSource = uri;
if (decodePixelWidth > 0) image.DecodePixelWidth = decodePixelWidth;
image.EndInit();
Add the following line to your loading code:
image.CacheOption = BitmapCacheOption.OnLoad;
This will load open the file, read it into memory, and close it all during image.EndInit. The default of BitmapCacheOption.Default has the odd behavior of opening the file, reading it into memory, but not yet closing it during image.EndInit.
Now i'm not sure if this can be applied to BitmapImage but i had a very similar problem with saving a modified image to the original file in GDI+ here
The method of loading the image from file keeps a lock open on the file until the image object is disposed.
Maybe it's the same thing with bitmapimage.urisource. Without playing around could you copy the image in memory and dispose the original thus unlocking the file?
Setting CacheOption to BitmapCacheOption.OnLoad, will not solve your problem. I think there is a bug, but I had the same problem. Finally i loaded my image to a memory stream and disposed the BitmapImage before saving the image to the file.