How to assign StreamSource to BitmapImage in codebehind? - c#

I have zip file in whick I store FlowDocument (Card.xaml) and folder with images (Media). Images in my FlowDocument have Tag, in which stores their path relative to FlowDocument. For image searching in FlowDocument (FindImages method): Finding all images in a FlowDocument
How I open this zip in RichTextBox. Please pay attention on how I create this images (bitmap), maybe problem there, but i can't understand what's wrong:
string nameOfXamlCardDefault = "Card.xaml";
private void Open_Executed(object sender, ExecutedRoutedEventArgs e)
{
OpenFileDialog dlg = new OpenFileDialog();
if (dlg.ShowDialog() == true)
{
//Open zip file
using (FileStream fullCardZipFile = File.Open(dlg.FileName, FileMode.Open, FileAccess.ReadWrite))
{
//Open zip by ZipArchive
using (ZipArchive archive = new ZipArchive(fullCardZipFile, ZipArchiveMode.Update))
{
//Get entry for xaml (FlowDocument)
ZipArchiveEntry xamlFileEntry = archive.GetEntry(nameOfXamlCardDefault);
//Open xaml
using (Stream xamlFileStreamInZip = xamlFileEntry.Open())
{
//Load FlowDocument into rtbEditor.Document
rtbEditor.Document = XamlReader.Load(xamlFileStreamInZip) as FlowDocument;
//Searching images
List<Image> images = FindImages(rtbEditor.Document).ToList();
foreach (var image in images)
{
var imageFileEntry = archive.GetEntry(image.Tag.ToString());
var bitmap = new BitmapImage();
using (Stream imageFileStream = imageFileEntry.Open())
{
var memoryStream = new MemoryStream();
imageFileStream.CopyTo(memoryStream);
bitmap.BeginInit();
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.StreamSource = memoryStream;
bitmap.EndInit();
image.Source = bitmap;
}
}
}
}
}
}
return;
}
All images in RichTextBox displays well, but there is no StreamSource in BitmapImage. And it will lead to error later:
<FlowDocument xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" NumberSubstitution.CultureSource="User" AllowDrop="True" PagePadding="5,0,5,0">
<Paragraph>
<Image Tag="Media/image0.png">
<Image.Source>
<BitmapImage CacheOption="OnLoad" BaseUri="{x:Null}"/>
</Image.Source>
</Image>
<Image Tag="Media/image1.png">
<Image.Source>
<BitmapImage CacheOption="OnLoad" BaseUri="{x:Null}"/>
</Image.Source>
</Image>
</Paragraph>
If just copy image and paste in RichTextBox, then it looks like this and this is good:
<Image Height="400" Width="600">
<Image.Source>
<BitmapImage CacheOption="OnLoad" UriSource="./Image1.bmp"
BaseUri="pack://payload:,,wpf1,/Xaml/Document.xaml"/>
</Image.Source>
Is it possible to embed images from zip like copy them and paste? I tried to use Clipboard and worked with MemoryStream. But it didn't help.

You should rewind the MemoryStream after copying the bitmap data, by setting its Position property or calling its Seek() method.
var imageFileEntry = archive.GetEntry(image.Tag.ToString());
if (imageFileEntry != null)
{
using (var imageFileStream = imageFileEntry.Open())
using (var memoryStream = new MemoryStream())
{
imageFileStream.CopyTo(memoryStream);
memoryStream.Position = 0; // here
var bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.StreamSource = memoryStream;
bitmap.EndInit();
image.Source = bitmap;
}
}
Instead of a BitmapImage, you could also decode a BitmapFrame from the stream.
var imageFileEntry = archive.GetEntry(image.Tag.ToString());
if (imageFileEntry != null)
{
using (var imageFileStream = imageFileEntry.Open())
using (var memoryStream = new MemoryStream())
{
imageFileStream.CopyTo(memoryStream);
memoryStream.Position = 0;
image.Source = BitmapFrame.Create(
memoryStream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
}
}

Related

DataPackageView Bitmap looses transparency

Using the .NET framework, when retrieving the image from the clipboard by converting the IRandomAccessStreamReference, the transparency on .PNG images is lost. How can i prevent this?
var content = Windows.ApplicationModel.DataTransfer.Clipboard.GetContent();
if (content.Contains(StandardDataFormats.Bitmap))
{
IRandomAccessStreamReference imageReceived = await content.GetBitmapAsync();
BitmapImage bitmap = null;
using (IRandomAccessStreamWithContentType imageStream = await imageReceived.OpenReadAsync())
{
bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.StreamSource = imageStream.AsStream();
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.EndInit();
bitmap.Freeze();
}
}

How do I save a complete InkCanvas?

I am trying to save a drawing from InkCanvas. I also implemented zoom capabilities and scrollbars to increase the size of the InkCanvas. The picture that is saved depends on the zoom, and, even when the size is the original, it does not save the complete InkCanvas.
XAML for InkCanvas:
<ScrollViewer Grid.Row="2" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<Border x:Name="brd_borger" MouseWheel="cnv_MouseWheel" Background="Aqua" Height="Auto" Width="Auto">
<InkCanvas x:Name="cnv" Width="Auto" Height="Auto" Background="Aqua"
PreviewMouseLeftButtonDown="cnv_MouseLeftButtonDown"
PreviewMouseRightButtonDown="cnv_MouseRightButtonDown"
SelectionChanged="cnv_SelectionChanged"
SelectionMoving="cnv_SelectionMoving"
SelectionMoved="cnv_SelectionMoved"
EditingMode="None">
</InkCanvas>
</Border>
</ScrollViewer>
Zooming Code:
private void cnv_MouseWheel(object sender, MouseWheelEventArgs e)
{
if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
{
var matrix = cnv.LayoutTransform.Value;
if (e.Delta > 0)
{
matrix.ScaleAt(1.5, 1.5, e.GetPosition(this).X, e.GetPosition(this).Y);
}
else
{
matrix.ScaleAt(1.0/1.5, 1.0/1.5, e.GetPosition(this).X, e.GetPosition(this).Y);
}
cnv.LayoutTransform = new MatrixTransform(matrix);
}
}
Saving Code:
private void Save_Click(object sender, RoutedEventArgs e)
{
SaveFileDialog dlg = new SaveFileDialog();
dlg.DefaultExt = ".png";
dlg.Filter = ODLG_FILTER_IMAGES;
Nullable<bool> result = dlg.ShowDialog();
if (result == true)
{
string filename = dlg.FileName;
MemoryStream ms = new MemoryStream();
FileStream fs = new FileStream(filename, FileMode.Create);
RenderTargetBitmap rtb = new RenderTargetBitmap((int)cnv.Width, (int)cnv.Height, 96d, 96d, PixelFormats.Default);
rtb.Render(cnv);
BmpBitmapEncoder encoder = new BmpBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(rtb));
encoder.Save(fs);
fs.Close();
}
}
Since you don't want the size of the image to be the same as the actual size of the InkCanvas, you need to specify the actual target image size somwhere. You could then use a DrawingContext and a VisualBrush to create the image:
private void Save_Click(object sender, RoutedEventArgs e)
{
SaveFileDialog dlg = new SaveFileDialog();
dlg.DefaultExt = ".png";
dlg.Filter = ODLG_FILTER_IMAGES;
if (dlg.ShowDialog() == true)
{
string filename = dlg.FileName;
MemoryStream ms = new MemoryStream();
FileStream fs = new FileStream(filename, FileMode.Create);
//define your image size here...
const int Width = 200;
const int Height = 200;
RenderTargetBitmap rtb = new RenderTargetBitmap(Width, Height, 96d, 96d, PixelFormats.Default);
Rect bounds = VisualTreeHelper.GetDescendantBounds(cnv);
DrawingVisual dv = new DrawingVisual();
using (DrawingContext ctx = dv.RenderOpen())
{
VisualBrush vb = new VisualBrush(cnv);
ctx.DrawRectangle(vb, null, new Rect(new Point(), bounds.Size));
}
rtb.Render(dv); ;
BmpBitmapEncoder encoder = new BmpBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(rtb));
encoder.Save(fs);
fs.Close();
}
}

Wpf Image Control blocks the file

I have a simple Window with button and second Window is opened when I click on the Button. Second Window has a Image control, which displays a .png-file. So if I use FileObject property for Binding all is OK, I can delete file from File Explorer. But if I use FileName property for Binding I cannot delete file from File Explorer, I get OS exception. I cannot do this even if I close second window, even if I invoke GC explicitly.
What is the problem with FileName property? Any ideas?
Win 7, Net 4.0
Window1
<Grid>
<Button Content="Ok"
Width="100"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Click="Click"
Padding="0,2,0,2"
IsDefault="True"
Name="_btnOk"/>
</Grid>
public partial class Window : Window
{
public Window()
{
InitializeComponent();
DataContext = this;
}
private void Click(Object sender, RoutedEventArgs e)
{
var window = new Window3();
window.ShowDialog();
}
}
Window2
<Grid>
<Image Source="{Binding FileObject}"></Image>
</Grid>
public partial class Window2 : Window
{
public Window2()
{
InitializeComponent();
DataContext = this;
FileName = "D:/pdf/myfile.png";
Closing += Window2_Closing;
}
public String FileName { get; set; }
public Object FileObject
{
get
{
if (String.IsNullOrEmpty(FileName))
return null;
if (!File.Exists(FileName))
return null;
var ms = new MemoryStream();
var bi = new BitmapImage();
using (var fs = new FileStream(FileName, FileMode.Open, FileAccess.Read))
{
fs.CopyTo(ms);
bi.BeginInit();
bi.StreamSource = ms;
bi.EndInit();
}
return bi;
}
}
void Window2_Closing(Object sender, System.ComponentModel.CancelEventArgs e)
{
GC.Collect();
GC.WaitForPendingFinalizers();
}
}
When you bind the Image.Source property to an Uri (or a string, from which an Uri is created internally), WPF uses a built-in type converter that creates a BitmapFrame from the Uri.
If the Uri contains a path to a local file, the BitmapFrame keeps the file open, as long as it is existing. This may be longer than it is actually used in your application, because it may by cached by WPF.
When you need to be able to delete the file that an image was loaded from, you should always use your FileObject approach, but it should look like this:
public ImageSource Image
{
get
{
...
var bi = new BitmapImage();
using (var fs = new FileStream(FileName, FileMode.Open, FileAccess.Read))
{
bi.BeginInit();
bi.CacheOption = BitmapCacheOption.OnLoad;
bi.StreamSource = fs;
bi.EndInit();
}
return bi;
}
}
Or like this:
public ImageSource Image
{
get
{
using (var fs = new FileStream(FileName, FileMode.Open, FileAccess.Read))
{
return BitmapFrame.Create(
fs, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
}
}
}
Or you bind to the FileName property with a binding converter that creates a BitmapImage or BitmapFrame as shown above.
use this code, I will explain later what is the problem.
var image = new BitmapImage();
image.BeginInit();
image.CacheOption = BitmapCacheOption.OnLoad;
image.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
image.UriSource = new Uri(FilePath);
image.EndInit();
return image;
You can solve this problem directly from xaml.
<Image>
<Image.Source>
<BitmapImage
CacheOption="OnLoad"
UriSource="{Binding FileName}" />
</Image.Source>
</Image>

how to rotate image in File in C# & WPF application

I have WPF and C# application. which captures the images and Save in to file(*.jpg).
I have the image path and i want to rotate image saved in File through the c# code.
and Save the Rotated image in same file.
How can i do that?
Use the rotate flip method.
E.g.:
Bitmap bitmap1 = (Bitmap)Bitmap.FromFile(#"C:\test.jpg");
bitmap1.RotateFlip(RotateFlipType.Rotate180FlipNone);
bitmap1.Save(#"C:\Users\Public\Documents\test rotated.jpg");
you can use my method:
BitmapImage rotateImage(string filename,int angle)
{
WIA.ImageFile img = new WIA.ImageFile();
img.LoadFile(filename);
WIA.ImageProcess IP = new WIA.ImageProcess();
Object ix1 = (Object)"RotateFlip";
WIA.FilterInfo fi1 = IP.FilterInfos.get_Item(ref ix1);
IP.Filters.Add(fi1.FilterID, 0);
Object p1 = (Object)"RotationAngle";
Object pv1 = (Object)angle;
IP.Filters[1].Properties.get_Item(ref p1).set_Value(ref pv1);
img = IP.Apply(img);
File.Delete(filename);
img.SaveFile(filename);
BitmapImage imagetemp = new BitmapImage();
using (var stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
{
imagetemp.BeginInit();
imagetemp.CacheOption = BitmapCacheOption.OnLoad;
imagetemp.StreamSource = stream;
imagetemp.EndInit();
}
return imagetemp;
}
usage:
string filename = System.AppDomain.CurrentDomain.BaseDirectory + "4.jpg";
image.Source = rotateImage(filename,90);

Generating thumbnail images in WPF

How do I generate a thumbnail image in WPF in the following scenario?
using (MemoryStream mem = new MemoryStream(imgbytes))
{
BitmapImage jpgimage = new BitmapImage();
jpgimage.BeginInit();
jpgimage.CacheOption = BitmapCacheOption.OnLoad;
jpgimage.StreamSource = mem;
jpgimage.EndInit();
Image wpfimage = new Image();
wpfimage.Source = jpgimage.Clone();
lbx.Items.Add(wpfimage);
lbx.UpdateLayout();
Thread.Sleep(1000);
}
This one worked perfectly for me
<Image Width="120" Height="120" HorizontalAlignment="Center">
<Image.Source>
<BitmapImage DecodePixelWidth="100" DecodePixelHeight="100" UriSource="Garden.jpg" />
</Image.Source>
</Image>
Here's some code I'm using to convert an image I've downloaded from the web to a thumbnail image. Does this help? Presumably you can cut out the bits where I save it to file.
using (var ms = new MemoryStream(e.Result))
{
var bi = new BitmapImage();
bi.BeginInit();
bi.StreamSource = ms;
bi.DecodePixelWidth = _maxThumbnailWidth;
bi.EndInit();
var encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bi));
using (var fs = new FileStream(filename, FileMode.Create))
{
encoder.Save(fs);
}
}

Categories

Resources