Silverlight image loading problems - c#

I simply cannot load Silverlight images synchronously. ImageOpened is all well and good but it doesn't really help me if if I have 20 textures to load BEFORE the app is allowed to execute! You cannot use threads as it causes multiple cross domain / cross thread exceptions. I have solved it but I am v curious as to how anyone else has tackled this.
My requirement is to load a jpeg / png / whatever into a pixel array, as i say, asynchronous options are a no go as I NEED the pixels before I start rendering.
Help!

you didn't say, from where you load a jpeg / png / whatever. If from resource, you can try to load first to BitmapImage, but not by UriSource property. Just use a method SetSource() - for me it loads the image immediately.
For example:
using System.Windows.Media.Imaging;
using System.Windows.Resources;
BitmapImage bmp = new BitmapImage();
Uri uri = new Uri("/SilverlightApp1;component/Resources/foto.jpg", UriKind.Relative);
StreamResourceInfo sri = Application.GetResourceStream(uri);
bmp.SetSource(sri.Stream);
Image image = new Image();
image.Source = bmp;

Related

UWP: How to remove image from memory?

How to remove the previous image from memory?
Method for set image in images grid:
public async Task Show(KeyValuePair<Image, Storyboard> imageStoryboard)
{
if (isVisible)
{
return;
}
isVisible = true;
this.ImageComponent = imageStoryboard.Key;
// элемент показан сохраняем его страницу
Models.Page.Save(ImageData.Page, ImageData.NextPageLink);
BitmapImage _bitmapImage = await GetBitmapImage(ImageData.ThumbnailUrl);
// если высота неопределена вычисляем её
if (Height == 0)
{
PixelHeight = _bitmapImage.PixelHeight;
PixelWidth = _bitmapImage.PixelWidth;
CalcHeight();
}
// параметры изображения
ImageComponent.Width = App.Settings.side_size;
ImageComponent.Height = Height - MARGIN;
ImageComponent.Margin = new Thickness(0, MarginTop, 0, 0);
Grid.SetColumn(ImageComponent, Column);
ImageComponent.DataContext = ImageData;
ImageComponent.Source = _bitmapImage;
// анимация
imageStoryboard.Value.Stop();
imageStoryboard.Value.Begin();
}
I set new source ImageComponent.Source = _bitmapImage; but how remove previous image from memory?
When i load more and more images memory is lost and appliaction close. And when i load previous images they load is so so fasted.
This method for load image: https://pastebin.com/AWHpNCJU
You can't directly manipulate the memory, the application will periodically call the garbage cleanup GC.Collect to clean up unused resources. But this cleanup has a premise that the current object is no longer referenced. So please check if your image resources have not been released in time.
Here is the document about Garbage Collection and Performance.
You can remove image files from the image cache by setting all associated Image.Source values to null.
In order to optimize memory usage, try to use Uri as the source of the image instead of Stream, which is the content of the document:
To prevent images from being decoded more than once, assign image source property from Uniform Resource Identifier (URI) rather than using memory streams whenever you can. The XAML framework can associate the same Uniform Resource Identifier (URI) in multiple places with one decoded image, but it cannot do the same for multiple memory streams even if they contain the same data.
For this, some examples are provided in the documentation:
// use this
var bitmapImage = new BitmapImage();
myImage.Source = bitmapImage;
bitmapImage.UriSource = new URI("ms-appx:///static/posts/cool-image.png", UriKind.RelativeOrAbsolute);
// not this
var bitmapImage = new BitmapImage();
bitmapImage.UriSource = new URI("ms-appx:///static/posts/cool-image.png", UriKind.RelativeOrAbsolute);
myImage.Source = bitmapImage;
You also mentioned that memory will rise high when loading images. In this regard, you can use DecodePixelWidth/DecodePixelHeight to reduce the actual resolution of the image.
For example, if you get a 1080P image, but the size of the image control is only 100x100, if you do not modify the pixels of the image, it will cause unnecessary waste of resources. DecodePixelWidth/DecodePixelHeight can be used to limit the size of the image, which can effectively reduce the memory usage.
For more info on the Image class and performance, see Optimize image resources.
When you are trying the above methods and still can't effectively reduce your memory, please check the memory usage through Visual Studio's debugging tool, and take a snapshot to compare and see which objects have been released. This is a document about Use the Memory windows.
Best regards.

Instagram Photo Effects in Windows 8 metro apps using c#

I need to implement Instagram photo effects like amaro, hudson, sepia, rise, and so on. I know this article only use basic effects: http://code.msdn.microsoft.com/windowsdesktop/Metro-Style-lightweight-24589f50
Another way suggested by people are to implement Direct2d and then apply using that. But for that I would need to write C++ code, where I have zero experience.
Can anyone suggest some other way to implement Instagram effects in c#?
Is there any built in c++ file for these effects?
Please see this example from CodeProject : Metro Style Lightweight Image Processing
The above example contains these image effects.
Negative
Color filter
Emboss
SunLight
Black & White
Brightness
Oilpaint
Tint
Please note above example seems to be implemented on either developer preview or release preview of Windows 8. So you will get error like this
'Windows.UI.Xaml.Media.Imaging.WriteableBitmap' does not contain a
constructor that takes 1 arguments
So you have to create instance of WriteableBitmap by passing pixel height and pixel width of image. I have edited the sample and it is working for me. You have to change wb = new WriteableBitmap(bs); to wb = await GetWB();
StorageFile originalImageFile;
WriteableBitmap cropBmp;
public async Task<WriteableBitmap> GetWB()
{
if (originalImageFile != null)
{
//originalImageFile is the image either loaded from file or captured image.
using (IRandomAccessStream stream = await originalImageFile.OpenReadAsync())
{
BitmapImage bmp = new BitmapImage();
bmp.SetSource(stream);
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(stream);
byte[] pixels = await GetPixelData(decoder, Convert.ToUInt32(bmp.PixelWidth), Convert.ToUInt32(bmp.PixelHeight));
cropBmp = new WriteableBitmap(bmp.PixelWidth, bmp.PixelHeight);
Stream pixStream = cropBmp.PixelBuffer.AsStream();
pixStream.Write(pixels, 0, (int)(bmp.PixelWidth * bmp.PixelHeight * 4));
}
}
return cropBmp;
}
Let me know if you are facing any problem.

WPF and MJPEG Decoder Help

This might be a little of a long shot, but here goes: I have a WPF project and need to stream MJPEG video. The library at http://mjpeg.codeplex.com/ seems to be one of the few PnP options. It works great for viewing a single stream. But, when you try to switch from one URI, to a second URI the end result is that you get frames from BOTH streams interlaced into the same image object on my WPF page. Both streams are live, not just a cache of the previous stream.
No matter what I try it seems like the first stream will not go away and the stopstream method in the decoder doesn't do a damn thing other than set a boolean value.
Here's is the pseudo code for how I'm using the library. Am I doing something wrong?
button_click{
//Create new decoder instance
//Remove the previous image object from my WPF page
//Add a new image object to the WPF page
//Stop stream
//Set the event for a new frams
//Request the new stream with a new URI
}
I have written to the decoder author with no response. I'm hoping that someone else that has used this library will be able to shed light on this.
If you call StopStream(), wait a bit, and then call ParseStream again, it should shut down the first stream, and only display the second one.
The better alternative would be to only use a single instance of MjpegDecoder for each stream you would like to view.
Of course, if you aren't sure how it works, you can just download the code, and see how it works.
Although the MJPEGDecoder library is great, it unfortunately creates a WPF BitmapImage and a System.Drawing.Bitmap at each frame. This is way too much.
What we need is a byte array, which is platform independant. Then it is up to the UI to convert it to an actual Image object.
So I took the AForge.NET MJPEGStream.cs object and tweaked it a bit so it sends a byte array instead of a Bitmap.
MJPEGStream.cs is robust as hell and very fast. I am using it in production to stream up to 30 streams. It automatically stops and restarts the stream as the URI changes, retries by itself if the cam stops responding...
Please take this gist, then use it this way :
var stream = new MJPEGStream("http://webcam.st-malo.com/axis-cgi/mjpg/video.cgi?resolution=352x288");
stream.NewFrame += img => {
Dispatcher.BeginInvoke(
System.Windows.Threading.DispatcherPriority.Render,
new Action(() => {
var bmp = new BitmapImage();
bmp.BeginInit();
bmp.StreamSource = new MemoryStream(img);
bmp.EndInit();
bmp.Freeze();
pic.Source = bmp;
}));
};
stream.Start();
Of course, have look on the documentation to benefit all its features.

image processing

i have some images..if these images are selected then it should generate another image which is the combination of all the selected images..
can anyone suggest as how to start with?
thanks
Use someting like that:
public void MergeImages(string FirstFileName, string SecondFileName)
{
Image firstImg = Image.FromFile(#"C:\temp\pic1.jpg");
Image secondImg = Image.FromFile(#"C:\temp\pic2.jpg");
Bitmap im1 = new Bitmap(firstImg);
Bitmap im2 = new Bitmap(secondImg);
Bitmap result = new Bitmap(im1.Width + im2.Width, (im1.Height > im2.Height) ? im1.Height : im2.Height);
Graphics gr = Graphics.FromImage(result);
gr.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear;
gr.DrawImage(firstImg, 0, 0);
gr.DrawImage(secondImg, im1.Width + 1, 0);
gr.Save();
result.Save(#"C:\test.jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
}
this code merges two images in one, systeming them into line.
i used ImageMagick to do these kind of things (http://www.imagemagick.org/Usage/layers/)
It is however a little bit different then using gdi to create images, but it is a very fast (and when you get used to the imagemagick syntax) and powerful way to edit images.
Normally you use gdi to edit images in memory; imagemagick uses a commandline utility to create images.
So for example you want to layer two images on top, you start a new process in your code in which you fire up a imagemagick proces with the right parameters and then the image is created ON DISK.
Then you can server the created image with a response.writebinary.

Problems overwriting (re-saving) image when it was set as image source

Good day all,
I am having some trouble with image permissions.
I am loading an image from file, resizing it and then saving it out to another folder.
I am then displaying this like so:
uriSource = new Uri(Combine(imagesDirectoryTemp, generatedFileName), UriKind.Absolute);
imgAsset.Source = new BitmapImage(uriSource);
This is working fine, the trouble comes if the user then selects another image immediately after and tries to save it over the original file.
An exception is generated upon saving my image "ExternalException: A generic error occurred in GDI+."
After some playing around i have narrowed the error down to imgAsset.Source = new BitmapImage(uriSource); as removing this line and not setting the imagesource will allow me to overwrite this file many times.
I have also tried setting the source to something else, before re-saving in the hope that the old reference would be disposed, this was not the case.
How can i get past this error?
Thanks,
Kohan
Edit
Now using this code i am not getting the exception however the image source is not updating. Also since i am not using a SourceStream, im not sure what i need to dispose of to get this working.
uriSource = new Uri(Combine(imagesDirectoryTemp, generatedFileName), UriKind.Absolute);
imgTemp = new BitmapImage();
imgTemp.BeginInit();
imgTemp.CacheOption = BitmapCacheOption.OnLoad;
imgTemp.UriSource = uriSource;
imgTemp.EndInit();
imgAsset.Source = imgTemp;
You're almost there.
Using BitmapCacheOption.OnLoad was the best solution to keep your file from being locked.
To cause it to reread the file every time you also need to add BitmapCreateOptions.IgnoreImageCache.
Adding one line to your code should do it:
imgTemp.CreateOption = BitmapCreateOptions.IgnoreImageCache;
thus resulting in this code:
uriSource = new Uri(Combine(imagesDirectoryTemp, generatedFileName), UriKind.Absolute);
imgTemp = new BitmapImage();
imgTemp.BeginInit();
imgTemp.CacheOption = BitmapCacheOption.OnLoad;
imgTemp.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
imgTemp.UriSource = uriSource;
imgTemp.EndInit();
imgAsset.Source = imgTemp;
When you load an Image in any WPF control it let's handle to your image and doesn't release it until you close your application. The reason for this... I dont know exactly, problably is relaying on some DirectX code behind the scene which never knows when the WPF application releases the image..
Use this code to load the image..
MemoryStream mstream = new MemoryStream();
System.Drawing.Bitmap bitmap = new Bitmap(imgName);
bitmap.Save(mstream, System.Drawing.Imaging.ImageFormat.Jpeg);
bitmap.Dispose(); // Releases the file.
mstream.Position = 0;
image.BeginInit();
image.StreamSource = mstream;
image.EndInit();
this.img.Source = image ;
it worked for me..
Sounds very much like the problem I had developing Intuipic, where WPF would not dispose of the image, thus locking the file. Check out this converter I wrote to deal with the problem.

Categories

Resources