Okay I have a an wpf image object, and it displays live images. So I have used a timer to refresh the image.
public void LoadLiveImage()
{
System.Windows.Media.PixelFormat pf = PixelFormats.Bgr24;
int stride = 4 * ((24 * cameraFrame.img_width + 31) / 32);
BitmapSource bmpImage= BitmapSource.Create(cameraFrame.img_width, cameraFrame.img_height, cameraFrame.img_width, cameraFrame.img_height, pf, null, cameraFrame.img_pixel, stride);
RemoteCameraImage.Source = bmpImage;
}
void dispatcherTimer_Tick(object sender, EventArgs e)
{
LoadLiveImage();
}
No issues, this is working fine.
However, I tried to move this to a thread and no image is displayed.
private void showLiveImage()
{
while (this.isCameraViewOpen)
{
if (RemoteCameraImage.Dispatcher.CheckAccess())
{
System.Windows.Media.PixelFormat pf = PixelFormats.Bgr24;
int stride = 4 * ((24 * cameraFrame.img_width + 31) / 32);
BitmapSource bmpImage = BitmapSource.Create(cameraFrame.img_width, cameraFrame.img_height, cameraFrame.img_width, cameraFrame.img_height, pf, null, cameraFrame.img_pixel, stride);
RemoteCameraImage.Source = bmpImage;
System.Threading.Thread.Sleep(5);
}
else
this.RemoteCameraImage.Dispatcher.Invoke(DispatcherPriority.Normal, new ImageUpdater(this.showLiveImage));
}
}
The showLiveImage isrunning as a thread. The image is received, there is not problem in that. I tested by saving the img_pixel array to a bmp file and file is generated. Just that the image is not displayed on. So I put a messagebox to be shown after the source is assigned, and then I m able to see the image on Image object. SO I think the problem I increased the Sleep time, but even the image is not refreshed. WHAT could be the issue?
EDIT:
After moving the code which was updating the image to another function, it works fine. And I used BeginInvoke() instead of invoke an all works fine.
Sometime ago I had similiar problems and I found this on Stackoverflow, which sovled it for me
Images on second thread
WPF Dispatcher {"The calling thread cannot access this object because a different thread owns it."}
If you have no intention of modifying the image once you have created
it you can freeze it using Freezable.Freeze and then assign to
GeneratedImage in the dispatcher delegate (the BitmapImage becomes
read-only and thus threadsafe as a result of the Freeze). The other
option would be to load the image into a MemoryStream on the
background thread and then create the BitmapImage on the UI thread in
the dispatcher delegate with that stream and the StreamSource property
of BitmapImage.
Try to use the Application.Current.Dispatcher instead of the one you used.
I believe this will do the trick.
Cheers
Related
I want to run asynchronous uploads with a progress bar in WPF (and preferably use PCL for code reuse in Xamarin and SL too.)
I've been trying to use System.Net.HttpClient.
Unfortunately, PutAsync doesn't provide any progress notifications. (I know that it does for Windows.Web.Http.HttpClient, but that's not available for WPF, nor in the PCL).
For downloading, its fairly easy to implement your own progress bar, as described here. You just pass the ResponseHeadersRead option, which makes the stream available as soon as the headers are returned, and then you read it in chunk by chunk, incrementing your progress bar as you go. But for uploading, this technique doesn't work - you need to pass all your upload data into PutAsync in one go, so there's no chance to increment your counter.
I've also wondered about using HttpClient.SendAsync instead. I'd hoped I could just treat this like an asynchronous HttpWebRequest (in which you can increment the counter as you write to the HttpWebRequest.GetRequestStream as described here). But unfortunately HttpClient.SendAsync doesn't give you writeable stream, so that doesn't work.
So does HttpClient support uploads with a non-blocked UI and a progress bar? It seems like a modest need. Or is there another class I should be using? Thanks very much.
Assuming that HttpClient (and underlying network stack) isn't buffering you should be able to do this by overriding HttpContent.SerializeToStreamAsync. You can do something like the following:
const int chunkSize = 4096;
readonly byte[] bytes;
readonly Action<double> progress;
protected override async Task SerializeToStreamAsync(System.IO.Stream stream, System.Net.TransportContext context)
{
for (int i = 0; i < this.bytes.Length; i += chunkSize)
{
await stream.WriteAsync(this.bytes, i, Math.Min(chunkSize, this.bytes.Length - i));
this.progress(100.0 * i / this.bytes.Length);
}
}
In order to avoid being buffered by HttpClient you either need to provide a content length (eg: implement HttpContent.TryComputeLength, or set the header) or enable HttpRequestHeaders.TransferEncodingChunked. This is necessary because otherwise HttpClient can't determine the content length header, so it reads in the entire content to memory first.
On the phone 8 you also need to disable AllowAutoRedirect because WP8 has a bug in the way it handles redirected posts (workaround is to issue a HEAD first, get the redirected URL, then send the post to the final URL with AllowAutoRedirect = false).
Simple way to upload a file with progress
I had the same need, and after some tries found out that you can easily get byte-accurate upload progress by tracking the Position of the FileStream of the file that you are going to upload.
Here is one way to do that...
FileStream fileToUpload = File.OpenRead(#"C:\test.mp3");
HttpContent content = new StreamContent(fileToUpload);
HttpRequestMessage msg = new HttpRequestMessage{
Content=content,
RequestUri = new Uri(--yourUploadURL--)
}
bool keepTracking = true; //to keep tracking thread running
new Task(new Action(() => { progressTracker(fileToUpload, ref keepTracking); })).Start();
var result = httpClient.SendAsync(msg).Result;
keepTracking = false; //to stop the tracking thread
the function progressTracker() is defined as,
void progressTracker(FileStream streamToTrack, ref bool keepTracking)
{
int prevPos = -1;
while (keepTracking)
{
int pos = (int)Math.Round(100 * (streamToTrack.Position / (double)streamToTrack.Length));
if (pos != prevPos)
{
Console.WriteLine(pos + "%");
}
prevPos = pos;
Thread.Sleep(100); //only update progress every 100ms
}
}
on certain machines that vary in configuration (OS, graphics card and memory) I get an OutOfMemory exception. Some tests showed that there is no significant increase in virtual memory consumed. That's the piece of code where the exception is raised:
public override Size GetPreferredSize(Size proposedSize)
{
try
{
using (Graphics g = this.CreateGraphics())
{
SizeF measured = g.MeasureString(this.Text, this.Font); // <= OutOfMemoryException
measured += new SizeF(1, 1);
return measured.ToSize();
}
}
catch (OutOfMemoryException oom)
{
System.Diagnostics.Trace.WriteLine(oom.ToString());
}
return proposedSize;
}
The class is derived directly from label.
CreateGraphics() makes a call to the GDI+ function GdipCreateFromHWND which could in some cases return a status (3) that raises the OutOfMemoryException I face:
[EditorBrowsable(EditorBrowsableState.Advanced), SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
public static Graphics FromHwndInternal(IntPtr hwnd)
{
IntPtr zero = IntPtr.Zero;
int status = SafeNativeMethods.Gdip.GdipCreateFromHWND(new HandleRef(null, hwnd), out zero);
if (status != 0)
{
throw SafeNativeMethods.Gdip.StatusException(status); // status = 3 throws an OutOfMemoryException with text "Out of memory"
}
return new Graphics(zero);
}
But unfortunately I have not found documentation on the function and cases when it returns Out Of Memory.
The issue is at least repeatable on one customers machine very fast. All he has to do is click on a button that creates a new window where one of this derived Label is placed and which is used to display content in a WebBrowser control.
If you have any ideas that could help me find reasons of the exception it would be great!
Cheers,
Michael
The un-solution: Don't use Graphics. If your application runs SetCompatibleTextRenderingDefault(false) at startup (which it should, because it yields better text rendering), you should use TextRenderer.MeasureText instead of MeasureString, because otherwise you will use GDI+ for measuring and GDI for drawing which will create discrepancies between actual rendering and measurement.
Another solution could be not caching the Graphics object but caching the size. Since you are not using proposedSize anyway, simply measure the text whenever the Text or Font property change and return that cached value in GetPreferredSize.
This might work:
private Graphics _graphics;
protected override void OnPaint(PaintEventArgs e)
{
_graphics = e.Graphics;
base.OnPaint(e);
}
public override Size GetPreferredSize(Size proposedSize)
{
try
{
SizeF measured = _graphics.MeasureString(this.Text, this.Font);
measured += new SizeF(1, 1);
return measured.ToSize();
}
catch (OutOfMemoryException oom)
{
System.Diagnostics.Trace.WriteLine(oom.ToString());
}
return proposedSize;
}
The documentation at http://msdn.microsoft.com/en-us/library/system.windows.forms.control.creategraphics.aspx states "you cannot cache the Graphics object for reuse, except to use non-visual methods like Graphics.MeasureString", which is exactly what you are trying to do. This will fail if GetPreferredSize is called before the control is painted, and you'll want to Dispose the Graphics object, but maybe this will help get you closer to a viable solution.
I have following image resize and save code.
This code is executed in different thread in ASP.NET MVC Project. As
using (FileStream fs = new FileStream(file.File.FullName,
FileMode.Open, FileAccess.Read, FileShare.Read))
{
BitmapDecoder decoder = BitmapDecoder.Create(fs,
BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.None);
var img = decoder.Frames[0];
img.Freeze();
double width = Size;
double height = Size;
if (img.PixelWidth > img.PixelHeight)
{
height = (int)(((double)img.PixelHeight / (double)img.PixelWidth)
* (double)width);
}
else
{
width = (int)(((double)img.PixelWidth / (double)img.PixelHeight)
* (double)height);
}
var target = new TransformedBitmap(img,
new ScaleTransform(width / (double)img.PixelWidth, height
/ (double)img.PixelHeight, 0, 0));
RenderOptions.SetBitmapScalingMode(target, BitmapScalingMode.HighQuality);
var t = BitmapFrame.Create(target);
RenderOptions.SetBitmapScalingMode(t, BitmapScalingMode.HighQuality);
target.Freeze();
t.Freeze();
JpegBitmapEncoder enc = new JpegBitmapEncoder();
enc.Frames.Add(t);
enc.QualityLevel = 90;
using (FileStream fsout = saved.File.OpenWrite())
{
enc.Save(fsout);
}
}
I have used using around every IDisposable object, WPF objects do not implement IDisposable so I cant dispose them manually.
I read somewhere that calling Freeze will prevent memory leaks, but even after this, no improvement. Memory usage of this process keep on increasing.
What I need is, when an Image is uploaded, it has to be resized in 4 different resolutions, 150x150, 350x350, 700x700 and 1000x1000 , each of these resolutions are invoked parallely using Parallel.ForEach method.
My rest of website is just plain simple Database access using Entity Framework, which I doubt can cause any memory leak upto 3GB of memory usage.
I tried putting this in a loop in a stand-alone test program and followed the function with an explicit GC.Collect(). On .NET 4.5 at least, this shows that this code does not leak -- the memory stays steady after many many calls.
I think you'll need to look elsewhere in your code. You should try to profile it with Analyze > Launch Performance Wizard... and select .NET Memory Allocations and see what's using the memory.
For fun, I also tried .NET 3.5 and didn't experience a leak their either.
There is a website that contains a single image from a webcam. Each time the site is hit, the most current image of the webcam is displayed. I want to make a real time video by hitting the site continuously.
I have searched and tried several things but cannot get it to refresh at a reasonable rate.
public MainWindow()
{
InitializeComponent();
this.picUri = "http://someurl";
this.thWatchVideo = new Thread(new ThreadStart(Watch));
_image = new BitmapImage();
_image.BeginInit();
_image.CacheOption = BitmapCacheOption.None;
_image.UriCachePolicy = new RequestCachePolicy(RequestCacheLevel.BypassCache);
_image.CacheOption = BitmapCacheOption.OnLoad;
_image.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
_image.UriSource = new Uri(this.picUri);
_image.EndInit();
this.imgVideo.Source = _image;
this.thWatchVideo.Start();
}
public void Watch()
{
while(true)
{
UpdateImage();
}
}
public void UpdateImage()
{
if (this.imgVideo.Dispatcher.CheckAccess())
{
_image = new BitmapImage();
_image.BeginInit();
_image.CacheOption = BitmapCacheOption.None;
_image.UriCachePolicy = new RequestCachePolicy(RequestCacheLevel.BypassCache);
_image.CacheOption = BitmapCacheOption.OnLoad;
_image.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
_image.UriSource = new Uri(this.picUri);
_image.EndInit();
this.imgVideo.Source = _image;
}
else
{
UpdateImageCallback del = new UpdateImageCallback(UpdateImage);
this.imgVideo.Dispatcher.Invoke(del);
}
}
Problem is, this is too slow and takes too long to refresh and the app just hangs.
I got this to work in Windows Forms with the PictureBox control but cannot get it to work in WPF. I refuse to believe that WPF is inferior to forms.
This app will always just hang (whether winforms or WPF) because you've got an infinite loop running everything it does on the UI thread. Your app hangs because you're not allowing the UI thread any time to process user input (such as resizing the window or trying to close the app).
With regard to your performance: have you tried profiling your code? I suspect that the problem is to do with you repeatedly hammering a webserver for an image, since you're never likely to get enough requests-per-second to make any kind of real-time video from static images. (There's a reason that we have video streaming codecs!)
instead of recreating whole image try to change only UriSource property.
Check out my answer to this: Showing processed images from an IP camera
Also, make sure the communication is done on a separate thread.
I suggest that the Bitmap image is a dependency object being created on a non-GUI thread. You then invoke UpdateImage on the GUI thread. Since the bitmap image dependency object wasn't created on/(owned by) the GUI thread, you get the "different thread owns it" error.
How about this as a workaround?
Copy the image temporarily to a local file location in your Watch routine.
Add a Thread.Sleep to the watch routine so that you don't hammer the CPU with the endless loop on this thread.
Use BeginInvoke instead of Invoke.
Load and update the image in the UpdateImage routine so that the image and the imgVideo objects are on the GUI thread. Update the image by reading it from your local file copy.
Without knowing the specifics of how you make Watch run on its own thread (using Background worker?) I think this approach will work for you.
We are using the WPF FormattedText object to determine text size in a service that grabs the latest news headlines from an RSS feed. The text retrieved needs to be in a specified canvas size. The service runs the code every 10 seconds and uses up to 2 threads if one takes longer than that. I'm using TaskFactory (which I've overridden the LimitedConcurrencyLevelTaskScheduler to limit to the amount of threads I specified).
This works great, except after several days (the length is variable), we start to get the following exceptions. The same code was working fine before we started using TPL to make it mult-threaded.
I need help figuring out what this is caused by. A few thoughts I'm looking into are: thread collisions holding on to a TTF file, memory issue, the dispatcher (see the stack trace) isn't playing nicely with the TaskFactory, other??
We don't have good profiling setup, but we've looked at the TaskManager when the exception is occurring and memory usage looks normal.
My next attempt is to use the TextBlock object and see if the exception is avoided.
Error Message: The system cannot find the file specified
Error Source: WindowsBase
Error Target Site: UInt16 RegisterClassEx(WNDCLASSEX_D)
Exception Stack Trace:
at MS.Win32.UnsafeNativeMethods.RegisterClassEx(WNDCLASSEX_D wc_d)
at MS.Win32.HwndWrapper..ctor(Int32 classStyle, Int32 style, Int32 exStyle, Int32 x, Int32 y, Int32 width, Int32 height, String name, IntPtr parent, HwndWrapperHook[] hooks)
at System.Windows.Threading.Dispatcher..ctor()
at System.Windows.Threading.Dispatcher.get_CurrentDispatcher()
at System.Windows.Media.TextFormatting.TextFormatter.FromCurrentDispatcher(TextFormattingMode textFormattingMode)
at System.Windows.Media.FormattedText.LineEnumerator..ctor(FormattedText text)
at System.Windows.Media.FormattedText.DrawAndCalculateMetrics(DrawingContext dc, Point drawingOffset, Boolean getBlackBoxMetrics)
at System.Windows.Media.FormattedText.get_Metrics()
at
(my method using the FormattedText, which is in a loop)
private static Size GetTextSize(string txt, Typeface tf, int size)
{
FormattedText ft = new FormattedText(txt, new CultureInfo("en-us"), System.Windows.FlowDirection.LeftToRight, tf, (double)size, System.Windows.Media.Brushes.Black, null, TextFormattingMode.Display);
return new Size { Width = ft.WidthIncludingTrailingWhitespace, Height = ft.Height };
}
EDIT: so far I've tried placing a lock around the code that calls this function, and calling it inside the CurrentDispatcher.Invoke method like so:
return (Size)Dispatcher.CurrentDispatcher.Invoke(new Func<Size>(() =>
{
FormattedText ft = new FormattedText(txt, new CultureInfo("en-us"), System.Windows.FlowDirection.LeftToRight, tf, (double)size, System.Windows.Media.Brushes.Black, null, TextFormattingMode.Display);
return new Size { Width = ft.WidthIncludingTrailingWhitespace, Height = ft.Height };
}));
EDIT: I've found links to others having similar, but not the exact problem.
http://www.eggheadcafe.com/software/aspnet/31783898/problem-creating-an-bitmapsource-from-an-hbitmap-in-threaded-code.aspx ~having a similar problem, but no answers
System.Windows.Media.DrawingVisual.RenderOpen() erroring after a time ~having a similar problem, but no answers
http://connect.microsoft.com/VisualStudio/feedback/details/361469/net-3-5-sp1-breaks-use-of-wpf-under-iis# ~ similar exception, but we're not using 3.5SP1 or IIS 7.
I've also submitted this through the Microsoft Connect site (please vote for it if you are having a similar problem).
https://connect.microsoft.com/WPF/feedback/details/654208/wpf-formattedtext-the-system-cannot-find-the-file-specified-exception-in-a-service
EDIT: Response from Microsoft:
"WPF objects need to be created on Dispatcher threads, not thread-pool threads. We usually recommend dedicating a thread to run the dispatcher loop to service requests to create objects and return
them frozen. Thanks, WPF Team" ~ How would I implement this?
EDIT: final solution thanks to NightDweller
if(Application.Current == null) new Application();
(Size)Application.Current.Dispatcher.CurrentDispatcher.Invoke(new Func<Size>(() =>
{
...});
EDIT: When I deployed the change (new Application();), I got an error logged " Cannot create more than one System.Windows.Application instance in the same AppDomain."
Error Source: PresentationFramework
Error Target Site: Void .ctor()
A shot in the dark:
The stack trace seems to show that WPF does not find a Dispatcher in the thread executing GetTextSize, so it has to create a new one, which involves creating a handle to a window.
Calling this every 10 seconds means 8'640 threads, thus windows per day. According to Mark Russinovich, there is a limit of 32 K windows per session, which may explain the error in RegisterClassEx.
An idea to overcome this is to read the current dispatcher from your main thread and set it in your tasks.
Edit:
I had another look and it looks like one cannot set the Dispatcher of a thread (it's created automatically).
I'm sorry, I am unable to understand what is going on here.
In order to compute the text size, WPF needs a FormattedText instance, which is stored as a member of the Dispatcher class. The existing Dispatchers are stored in a list of weak references. Each one is associated with a specific thread.
Here, it looks like new Dispatcher instances are created many, many times.
So, either the calling thread is new or memory is quite low and the weak references have been discarded.
The first case (new thread) is unlikely as the task scheduler uses the thread pool, which has about 25 threads per core (if I remember correctly), which is not enough to deplete the pool of ATOMs or windows.
In the second case, the depletion of resource is unlikely as the HwndWrapper is IDisposable and the Dispose method takes care of freeing the registered class.
As you already know from the info you provided, All UI elements (FormattedText is one) have to be created on the UI thread.
The code you are looking for is:
return (Size)Application.Current.Dispatcher.CurrentDispatcher.Invoke(new Func<Size>(() =>
{
FormattedText ft = new FormattedText(txt, new CultureInfo("en-us"), System.Windows.FlowDirection.LeftToRight, tf, (double)size, System.Windows.Media.Brushes.Black, null, TextFormattingMode.Display);
return new Size { Width = ft.WidthIncludingTrailingWhitespace, Height = ft.Height };
}));
Notice the Application.Current - you want the "Application" dispatcher which is the dispatcher for the UI thread in WPF applications.
Your current code actually creates a dispatcher for the current thread so you didn't really change the executing thread (see here regarding the dispatcher)
Have you renamed anything? If yes, check that link: WPF Prism: Problem with creating a Shell