Using WPF Imaging classes - Getting image dimensions without reading the entire file - wpf

Link this post I want to be able to read an image files height and width without reading in the whole file into memory.
In the post Frank Krueger mentions there is a way of doing this with some WPF Imaging classes. Any idea on how to do this??

This should do it:
var bitmapFrame = BitmapFrame.Create(new Uri(#"C:\Documents and Settings\All Users\Documents\My Pictures\Sample Pictures\Winter.jpg"), BitmapCreateOptions.DelayCreation, BitmapCacheOption.None);
var width = bitmapFrame.PixelWidth;
var height = bitmapFrame.PixelHeight;

Following Sir Juice's recommendation, here is some alternative code that avoids locking the image file:
using (var stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
{
var bitmapFrame = BitmapFrame.Create(stream, BitmapCreateOptions.DelayCreation, BitmapCacheOption.None);
var width = bitmapFrame.PixelWidth;
var height = bitmapFrame.PixelHeight;
}

Related

Image original size WPF .NET

If I open an image using this code I get the correct width and height:
Bitmap bitmap = new Bitmap(#"C:\Users\Javier Escribano\Desktop\sample.png");
var imageHeight = bitmap.Height; //1270
var imageWidth = bitmap.Width; //1650
but If I use this code to show an image on WPF control the image is automatically resized. I want to keep the original dimensions:
ImageSource img = (ImageSource)new ImageSourceConverter().ConvertFromString(
#"C:\Users\Javier Escribano\Desktop\sample.png");
this.image.Source = img;
this.image.Width = img.Height; //1057
this.image.Height = img.Width; // 817
This is very likely caused by a mismatch of ppi (pixels per inch) of the png image and the dpi (dots per inch) of WPF. Scott Hanselman has a good post about it here.

byte[] to ImageSource stream

I need to convert byte[] to BitmapImage and show it in WPF image control. (img.Source = ...).
if i convert it like this:
m_photo = new BitmapImage();
using (MemoryStream stream = new MemoryStream(photo.ToArray()))
{
m_photo.BeginInit();
m_photo.StreamSource = stream;
m_photo.EndInit();
}
it can't do XAML binding to Source property because "m_photo owns another stream"... What can I do?
Set the cache option to OnLoad after begininit
m_photo.CacheOption = BitmapCacheOption.OnLoad;
EDIT: complete code for bmp array to Image source
DrawingGroup dGroup = new DrawingGroup();
using (DrawingContext drawingContext = dGroup.Open())
{
var bmpImage = new BitmapImage();
bmpImage.BeginInit();
bmpImage.CacheOption = BitmapCacheOption.OnLoad;
bmpImage.StreamSource = new MemoryStream(photoArray);
bmpImage.EndInit();
drawingContext.DrawImage(bmpImage, new Rect(0, 0, bmpImage.PixelWidth, bmpImage.PixelHeight));
drawingContext.Close();
}
DrawingImage dImage = new DrawingImage(dGroup);
if (dImage.CanFreeze)
dImage.Freeze();
imageControl.Source = dImage;
Ok, I just found solution. If use this code (converting byte[] to bitmapSource) in code of class - you have this error, that the object is in another stream. But if create a Converter (IValueConverter) and use it with same code of converting in XAML binding - everything ok!
Thanks everybody!

Creating tiff image at runtime in WPF

I'm trying to generate a simple tiff image at runtime. This image consists of white background and image downloaded from remote server.
Here's the code I've written for reaching that goal:
const string url = "http://localhost/barcode.gif";
var size = new Size(794, 1123);
var drawingVisual = new DrawingVisual();
using (var drawingContext = drawingVisual.RenderOpen())
{
drawingContext.DrawRectangle(new SolidColorBrush(Colors.White), null, new Rect(size));
var image = new BitmapImage(new Uri(url));
drawingContext.DrawImage(image, new Rect(0, 0, 180, 120));
}
var targetBitmap = new RenderTargetBitmap((int)size.Width, (int)size.Height, 96, 96, PixelFormats.Default);
targetBitmap.Render(drawingVisual);
var convertedBitmap = new FormatConvertedBitmap(targetBitmap, PixelFormats.BlackWhite, null, 0);
var encoder = new TiffBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(convertedBitmap));
using (var fs = new FileStream("out.tif", FileMode.Create))
{
encoder.Save(fs);
}
The code works and generates "out.tif" file. But the output file has just a white background, without image received from remote server.
What can be the problem? I have tried the following code in a variety of ways, but everytime with no luck.
I found this reading about the FormatConvertedBitmap class. Maybe give it a shot
FormatConvertedBitmap newFormatedBitmapSource = new FormatConvertedBitmap();
// BitmapSource objects like FormatConvertedBitmap can only have their properties
// changed within a BeginInit/EndInit block.
newFormatedBitmapSource.BeginInit();
// Use the BitmapSource object defined above as the source for this new
// BitmapSource (chain the BitmapSource objects together).
newFormatedBitmapSource.Source = targetBitmap;
// Set the new format to BlackWhite.
newFormatedBitmapSource.DestinationFormat = PixelFormats.BlackWhite;
newFormatedBitmapSource.EndInit();

Replace RichTextBox Text but keep formatting

Can anybody cast some light on this for me, I have a RichTextBox which im loading an xaml file into it. I need to Replace certain Parts of the RichTxtBox's text with real data i.e. '[our_name]' is replaced with 'Billie Brags'. My xaml file contains formatting like bold & font size.
When I run my code (shown below) I can change the text OK but im loosing the formatting.
Any idea how I can do this and keep the formatting?
Thank you
FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read);
using (fs)
{
TextRange RTBText = new TextRange(rtb_wording.Document.ContentStart, rtb_wording.Document.ContentEnd);
RTBText.Load(fs, DataFormats.Xaml);
}
TextRange tr = new TextRange(rtb_wording.Document.ContentStart, rtb_wording.Document.ContentEnd);
string rtbContent = tr.Text;
rtbContent = rtbContent.Replace("<our_name>", "Billie Brags");
System.Windows.MessageBox.Show(rtbContent);
FlowDocument myFlowDoc = new FlowDocument();
// Add paragraphs to the FlowDocument
myFlowDoc.Blocks.Add(new Paragraph(new Run(rtbContent)));
rtb_wording.Document = myFlowDoc;
Its working, this is how I did it in the end, not too pretty but it functions. WPF RTB really should have rtf property like winforms...
Thanks to Kent for putting me on the right track.
var textRange = new TextRange(rtb_wording.Document.ContentStart, rtb_wording.Document.ContentEnd);
string rtf;
using (var memoryStream = new MemoryStream())
{
textRange.Save(memoryStream, DataFormats.Rtf);
rtf = ASCIIEncoding.Default.GetString(memoryStream.ToArray());
}
rtf = rtf.Replace("<our_name>", "Bob Cratchet");
MemoryStream stream = new MemoryStream(ASCIIEncoding.Default.GetBytes(rtf));
rtb_wording.SelectAll();
rtb_wording.Selection.Load(stream, DataFormats.Rtf);
I believe you'll need to save the contents of the TextRange in RTF format, and then reload the contents of the RTB. I haven't tried this so not sure it will work (on linux at the moment so can't test):
var textRange = new TextRange(rtb.Document.ContentStart, rtb.Document.ContentEnd);
string rtf;
using (var memoryStream = new MemoryStream())
using (var streamReader = new StreamReader(memoryStream))
{
textRange.Save(memoryStream, DataFormats.Rtf);
rtf = streamReader.ReadToEnd();
}
rtf = rtf.Replace("<whatever>", "whatever else");
using (var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(rtf)))
{
textRange.Load(memoryStream, DataFormats.Rtf);
}

WPF, Canvas, FormattedText.BuildGeometry - why is nothing displayed?

I have a need to display text mixed with geometries - and so far I have the geometries displayed nicely (removed from example below), but the text doesn't show up at all.
I've found the example for formatted text below and think I should be able to take the buildGeometry and enclose it in a path to be shown in a canvas.
Can anybody help me see what I am doing wrong?
Thanks for any responses,
Anders, Denmark
var canvas = new Canvas();
var formattedText = new FormattedText(
"Hello world",
CultureInfo.GetCultureInfo("en-us"),
FlowDirection.LeftToRight,
new Typeface("Verdana"),
32,
Brushes.Black);
var buildGeometry = formattedText.BuildGeometry(new Point(500, 500));
var path = new System.Windows.Shapes.Path();
path.Data = buildGeometry;
canvas.Children.Add(path);
Content = canvas;
Ay caramba,
A Path needs a Stroke defined in order to show anything(!).
Apologies to all spending time on my question....
var path = new System.Windows.Shapes.Path
{
Stroke = Brushes.Black,
StrokeThickness = 1
};

Resources