Images loading partially - c#

I'm trying to load some 20 images in my WPF application. Only the first image loads completely. Other images are loading partially. When i used breakpoint to debug i tried to load each image after 2 seconds and that worked well.
Code
Images will be loaded like,
foreach (string path in ImagesCollection)
{
DisplayImage = LoadImage(path);
}
Load image method,
MemoryStream mem;
if (!string.IsNullOrEmpty(path) && (File.Exists(path)))
{
FileInfo ImageFile = new FileInfo(path);
ImageFile.Refresh();
if (mem != null)
{
mem.Dispose();
}
using (var stream = ImageFile.OpenRead())
{
mem = new MemoryStream();
stream.CopyTo(mem);
}
mem.Position = 0;
ImageFrame = BitmapFrame.Create(mem);
}
Screenshot:
I believe Dispose or a new instance makes the image doesn't load. Kindly help.

The documentation for BitmapFrame.Create state "The bitmapStream can be closed after the frame is created only when the OnLoad cache option is used. The default OnDemand cache option retains the stream until the frame is needed"
This means you cannot re-use the MemoryStream once you've passed it to the BitmapFrame. This is the source of the error.
For efficiency just pass the FileStream.
Load image method
if (!string.IsNullOrEmpty(path) && (File.Exists(path)))
{
var stream = ImageFile.OpenRead())
ImageFrame = BitmapFrame.Create(stream);
}

Related

xamarin.forms save file/image

coding xamarin form project and also using pcl storage. have problem with saving image or file on device all examples i found show how to save stream of byte array into file but non of them show how to turn convert image into usable format for saving.
var webImage = new Image();
webImage.Source = new UriImageSource
{
CachingEnabled = false,
Uri = new Uri("http://server.com/image.jpg"),
};
byte[] image = ????(what i need)????(webImage.Source);
// get hold of the file system
IFolder folder = rootFolder ?? FileSystem.Current.LocalStorage;
// create a file, overwriting any existing file
IFile file = await folder.CreateFileAsync(fileName, CreationCollisionOption.ReplaceExisting);
// populate the file with image data
using (System.IO.Stream stream = await file.OpenAsync(FileAccess.ReadAndWrite))
{
stream.Write(image, 0, image.Length);
}
In other words looking for code to save image/file on device from url.
Tried ffimageloading since it contain converter to byte[], but always get error:"Object reference not set to an instance of an object." for GetImageAsJpgAsync and GetImageAsPngAsync method. problem might be that image isn't fully loaded. but finish event and finish command never get called even trough image is fully loaded on screen and bound to cachedImage.
var cachedImage = new CachedImage()
{
Source = "https://something.jpg",
FinishCommand = new Command(async () => await TEST()),
};
cachedImage.Finish += CachedImage_Finish;
var image = await cachedImage.GetImageAsJpgAsync();
With FFImageLoading (I noticed you use it):
await ImageService.Instance.LoadUrl("https://something.jpg").AsJpegStream();
If you want to get original file location, use this:
await ImageService.Instance.LoadUrl("https://something.jpg").Success((imageInfo) => { //TODO imageInfo.FilePath } ).DownloadOnly();

Issue serializing new bitmap image in xml file [duplicate]

i've got some binary data which i want to save as an image. When i try to save the image, it throws an exception if the memory stream used to create the image, was closed before the save. The reason i do this is because i'm dynamically creating images and as such .. i need to use a memory stream.
this is the code:
[TestMethod]
public void TestMethod1()
{
// Grab the binary data.
byte[] data = File.ReadAllBytes("Chick.jpg");
// Read in the data but do not close, before using the stream.
Stream originalBinaryDataStream = new MemoryStream(data);
Bitmap image = new Bitmap(originalBinaryDataStream);
image.Save(#"c:\test.jpg");
originalBinaryDataStream.Dispose();
// Now lets use a nice dispose, etc...
Bitmap2 image2;
using (Stream originalBinaryDataStream2 = new MemoryStream(data))
{
image2 = new Bitmap(originalBinaryDataStream2);
}
image2.Save(#"C:\temp\pewpew.jpg"); // This throws the GDI+ exception.
}
Does anyone have any suggestions to how i could save an image with the stream closed? I cannot rely on the developers to remember to close the stream after the image is saved. In fact, the developer would have NO IDEA that the image was generated using a memory stream (because it happens in some other code, elsewhere).
I'm really confused :(
As it's a MemoryStream, you really don't need to close the stream - nothing bad will happen if you don't, although obviously it's good practice to dispose anything that's disposable anyway. (See this question for more on this.)
However, you should be disposing the Bitmap - and that will close the stream for you. Basically once you give the Bitmap constructor a stream, it "owns" the stream and you shouldn't close it. As the docs for that constructor say:
You must keep the stream open for the
lifetime of the Bitmap.
I can't find any docs promising to close the stream when you dispose the bitmap, but you should be able to verify that fairly easily.
A generic error occurred in GDI+.
May also result from incorrect save path!
Took me half a day to notice that.
So make sure that you have double checked the path to save the image as well.
Perhaps it is worth mentioning that if the C:\Temp directory does not exist, it will also throw this exception even if your stream is still existent.
Copy the Bitmap. You have to keep the stream open for the lifetime of the bitmap.
When drawing an image: System.Runtime.InteropServices.ExternalException: A generic error occurred in GDI
public static Image ToImage(this byte[] bytes)
{
using (var stream = new MemoryStream(bytes))
using (var image = Image.FromStream(stream, false, true))
{
return new Bitmap(image);
}
}
[Test]
public void ShouldCreateImageThatCanBeSavedWithoutOpenStream()
{
var imageBytes = File.ReadAllBytes("bitmap.bmp");
var image = imageBytes.ToImage();
image.Save("output.bmp");
}
I had the same problem but actually the cause was that the application didn't have permission to save files on C. When I changed to "D:\.." the picture has been saved.
You can try to create another copy of bitmap:
using (var memoryStream = new MemoryStream())
{
// write to memory stream here
memoryStream.Position = 0;
using (var bitmap = new Bitmap(memoryStream))
{
var bitmap2 = new Bitmap(bitmap);
return bitmap2;
}
}
This error occurred to me when I was trying from Citrix. The image folder was set to C:\ in the server, for which I do not have privilege. Once the image folder was moved to a shared drive, the error was gone.
A generic error occurred in GDI+. It can occur because of image storing paths issues,I got this error because my storing path is too long, I fixed this by first storing the image in a shortest path and move it to the correct location with long path handling techniques.
I was getting this error, because the automated test I was executing, was trying to store snapshots into a folder that didn't exist. After I created the folder, the error resolved
One strange solution which made my code to work.
Open the image in paint and save it as a new file with same format(.jpg). Now try with this new file and it works. It clearly explains you that the file might be corrupted in someway.
This can help only if your code has every other bugs fixed
It has also appeared with me when I was trying to save an image into path
C:\Program Files (x86)\some_directory
and the .exe wasn't executed to run as administrator, I hope this may help someone who has same issue too.
For me the code below crashed with A generic error occurred in GDI+on the line which Saves to a MemoryStream. The code was running on a web server and I resolved it by stopping and starting the Application Pool that was running the site.
Must have been some internal error in GDI+
private static string GetThumbnailImageAsBase64String(string path)
{
if (path == null || !File.Exists(path))
{
var log = ContainerResolver.Container.GetInstance<ILog>();
log.Info($"No file was found at path: {path}");
return null;
}
var width = LibraryItemFileSettings.Instance.ThumbnailImageWidth;
using (var image = Image.FromFile(path))
{
using (var thumbnail = image.GetThumbnailImage(width, width * image.Height / image.Width, null, IntPtr.Zero))
{
using (var memoryStream = new MemoryStream())
{
thumbnail.Save(memoryStream, ImageFormat.Png); // <= crash here
var bytes = new byte[memoryStream.Length];
memoryStream.Position = 0;
memoryStream.Read(bytes, 0, bytes.Length);
return Convert.ToBase64String(bytes, 0, bytes.Length);
}
}
}
}
I came across this error when I was trying a simple image editing in a WPF app.
Setting an Image element's Source to the bitmap prevents file saving.
Even setting Source=null doesn't seem to release the file.
Now I just never use the image as the Source of Image element, so I can overwrite after editing!
EDIT
After hearing about the CacheOption property(Thanks to #Nyerguds) I found the solution:
So instead of using the Bitmap constructor I must set the Uri after setting CacheOption BitmapCacheOption.OnLoad.(Image1 below is the Wpf Image element)
Instead of
Image1.Source = new BitmapImage(new Uri(filepath));
Use:
var image = new BitmapImage();
image.BeginInit();
image.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
image.CacheOption = BitmapCacheOption.OnLoad;
image.UriSource = new Uri(filepath);
image.EndInit();
Image1.Source = image;
See this: WPF Image Caching
Try this code:
static void Main(string[] args)
{
byte[] data = null;
string fullPath = #"c:\testimage.jpg";
using (MemoryStream ms = new MemoryStream())
using (Bitmap tmp = (Bitmap)Bitmap.FromFile(fullPath))
using (Bitmap bm = new Bitmap(tmp))
{
bm.SetResolution(96, 96);
using (EncoderParameters eps = new EncoderParameters(1))
{
eps.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L);
bm.Save(ms, GetEncoderInfo("image/jpeg"), eps);
}
data = ms.ToArray();
}
File.WriteAllBytes(fullPath, data);
}
private static ImageCodecInfo GetEncoderInfo(string mimeType)
{
ImageCodecInfo[] encoders = ImageCodecInfo.GetImageEncoders();
for (int j = 0; j < encoders.Length; ++j)
{
if (String.Equals(encoders[j].MimeType, mimeType, StringComparison.InvariantCultureIgnoreCase))
return encoders[j];
}
return null;
}
I used imageprocessor to resize images and one day I got "A generic error occurred in GDI+" exception.
After looked up a while I tried to recycle the application pool and bingo it works. So I note it here, hope it help ;)
Cheers
I was getting this error today on a server when the same code worked fine locally and on our DEV server but not on PRODUCTION. Rebooting the server resolved it.
public static byte[] SetImageToByte(Image img)
{
ImageConverter converter = new ImageConverter();
return (byte[])converter.ConvertTo(img, typeof(byte[]));
}
public static Bitmap SetByteToImage(byte[] blob)
{
MemoryStream mStream = new MemoryStream();
byte[] pData = blob;
mStream.Write(pData, 0, Convert.ToInt32(pData.Length));
Bitmap bm = new Bitmap(mStream, false);
mStream.Dispose();
return bm;
}

Windows Store App PDF Document does not render when stream disposed after load

I have a working solution to load and render a PDF document from a byte array in a Windows Store App. Lately some users have reported out-of-memory errors though. As you can see in the code below there is one stream I am not disposing of. I've commented out the line. If I do dispose of that stream, then the PDF document does not render anymore. It just shows a completely white image. Could anybody explain why and how I could load and render the PDF document and dispose of all disposables?
private static async Task<PdfDocument> LoadDocumentAsync(byte[] bytes)
{
using (var stream = new InMemoryRandomAccessStream())
{
await stream.WriteAsync(bytes.AsBuffer());
stream.Seek(0);
var fileStream = RandomAccessStreamReference.CreateFromStream(stream);
var inputStream = await fileStream.OpenReadAsync();
try
{
return await PdfDocument.LoadFromStreamAsync(inputStream);
}
finally
{
// do not dispose otherwise pdf does not load / render correctly. Not disposing though may cause memory issues.
// inputStream.Dispose();
}
}
}
and the code to render the PDF
private static async Task<ObservableCollection<BitmapImage>> RenderPagesAsync(
PdfDocument document,
PdfPageRenderOptions options)
{
var items = new ObservableCollection<BitmapImage>();
if (document != null && document.PageCount > 0)
{
for (var pageIndex = 0; pageIndex < document.PageCount; pageIndex++)
{
using (var page = document.GetPage((uint)pageIndex))
{
using (var imageStream = new InMemoryRandomAccessStream())
{
await page.RenderToStreamAsync(imageStream, options);
await imageStream.FlushAsync();
var renderStream = RandomAccessStreamReference.CreateFromStream(imageStream);
using (var stream = await renderStream.OpenReadAsync())
{
var bitmapImage = new BitmapImage();
await bitmapImage.SetSourceAsync(stream);
items.Add(bitmapImage);
}
}
}
}
}
return items;
}
As you can see I am using this RandomAccessStreamReference.CreateFromStream method in both of my methods. I've seen other examples that skip that step and use the InMemoryRandomAccessStream directly to load the PDF document or the bitmap image, but I've not managed to get the PDF to render correctly then. The images will just be completely white again. As I mentioned above, this code does actually render the PDF correctly, but does not dispose of all disposables.
Why
I assume LoadFromStreamAsync(IRandomAccessStream) does not parse the whole stream into the PdfDocument object but instead only parses the main PDF dictionaries and holds a reference to the IRandomAccessStream.
This actually is the sane thing to do, why parse the whole PDF into own objects (a possibly very expensive operation resource-wise) if the user eventually only wants to render one page, or even merely wants to query the number of pages...
Later on, when other methods of the returned PdfDocument are called, e.g. GetPage, these methods try to read the additional data from the stream they need for their task, e.g. for rendering. Unfortunately in your case that means after the finally { inputStream.Dispose(); }
How else
You have to postpone the inputStream.Dispose() until all operations on the PdfDocument are finished. That means some hopefully minor architectural changes for your code. Probably moving the LoadDocumentAsync code as a frame into the RenderPagesAsync method or its caller suffices.

Unlock file generated from Bitmap object

I have this method to get a thumbnail from an image on disk:
public static BitmapImage GetThumbnail()
{
var dlg = new OpenFileDialog {Filter = "Imágenes|" + extensionesImagenes};
var result = dlg.ShowDialog();
if (result == true)
{
var tempFolder = Path.GetTempPath() + "MyTempFolder\\";
if (!Directory.Exists(tempFolder))
Directory.CreateDirectory(tempFolder);
using (var thumbnail = new Bitmap(170, 170))
{
using (var gr = Graphics.FromImage(thumbnail))
{
gr.SmoothingMode = SmoothingMode.HighQuality;
gr.InterpolationMode = InterpolationMode.HighQualityBicubic;
gr.PixelOffsetMode = PixelOffsetMode.HighQuality;
gr.DrawImage(new Bitmap(dlg.FileName), new Rectangle(0, 0, 170, 170));
}
thumbnail.Save(tempFolder + "foto.jpg", ImageFormat.Jpeg);
}
return new BitmapImage(new Uri(tempFolder + "foto.jpg"));
}
return null;
}
If I run it for the first time there's no problem. But when I run it for the second time I get "A generic error occurred in GDI+" exception because the file is being used by my app.
The method could be invoked several times depending of the actions made by users and the file should be overwritten. As a matter of fact, if the file exist when I invoke the method for the first time it's successfully overwritten.
The file is generated by the Save() method of the Bitmap class and I'm not using any stream.
How can I unlock the file?
TIA
EDIT
I'm not using MemoryStream because I need the file in another method: when an user invokes the GetThumbnail method the thumbnail will be shown in a StackPanel (the thumbnail is the ImageSource of the StackPanel.)
Later the user could save to database the info shown in a WPF form, image included, and the method that saves to database need to read the bytes from the saved image.
EDIT 2
Before using thumbnails I was using this method:
public static BitmapImage GetImage()
{
var dlg = new OpenFileDialog {Filter = "Imágenes|" + extensionesImagenes};
var result = dlg.ShowDialog();
return result == true ? new BitmapImage(new Uri(dlg.FileName)) : null;
}
It was working ok.
Now that I'm using thumbnails the problem with a MemoryStream is that I can't set the Uri for the image.
For example I was using:
imagenNueva = InterfazUtil.GetImage(); // GetImage() is now GetThumbnail()
var rutaFoto = (imagenNueva != null) ? imagenNueva.ToString() : null;
The string rutaFoto was passed to the method that save the info to the database and it uses this variable to read the image from disk.
In the GetThumbnail method I did convert the Image thumbnail to a BitmapImage and I did try to set the SourceUri and BaseUri with:
new Uri(dialog.FileName);
But when I invoke imagenNueva.ToString() I don't get a valid Uri.
gr.DrawImage(new Bitmap(dlg.FileName), new Rectangle(0, 0, 170, 170));
Using a bitmap like that is very troublesome. It locks the "dlg.FileName" file and it will take a while before the garbage collector releases it. You'll need to write it like this instead:
using (var bmp = new Bitmap(dlg.FileName)) {
gr.DrawImage(bmp, new Rectangle(0, 0, 170, 170));
}
Now it gets disposed immediately after use and that releases the lock on the file as well.
Btw, you can completely avoid writing code like this if you use a MemoryStream instead. Just save the image to the MemoryStream so you don't need a file. Assuming the images are not that big or you can count on running on a 64-bit operating system. Not otherwise a reason to avoid disposing bitmaps.

Generating a multipage TIFF is not working

I'm trying to generate a multipage TIFF file from an existing picture using code by Bob Powell:
picture.SelectActiveFrame(FrameDimension.Page, 0);
var image = new Bitmap(picture);
using (var stream = new MemoryStream())
{
ImageCodecInfo codecInfo = null;
foreach (var imageEncoder in ImageCodecInfo.GetImageEncoders())
{
if (imageEncoder.MimeType != "image/tiff") continue;
codecInfo = imageEncoder;
break;
}
var parameters = new EncoderParameters
{
Param = new []
{
new EncoderParameter(Encoder.SaveFlag, (long) EncoderValue.MultiFrame)
}
};
image.Save(stream, codecInfo, parameters);
parameters = new EncoderParameters
{
Param = new[]
{
new EncoderParameter(Encoder.SaveFlag, (long) EncoderValue.FrameDimensionPage)
}
};
for (var i = 1; i < picture.GetFrameCount(FrameDimension.Page); i++)
{
picture.SelectActiveFrame(FrameDimension.Page, i);
var img = new Bitmap(picture);
image.SaveAdd(img, parameters);
}
parameters = new EncoderParameters
{
Param = new[]
{
new EncoderParameter(Encoder.SaveFlag, (long)EncoderValue.Flush)
}
};
image.SaveAdd(parameters);
stream.Flush();
}
But it's not working (only the first frame is included in the image) and I don't know why.
What I want to do is to change a particular frame of a TIFF file (add annotations to it).
I don't know if there's a simpler way to do it but what I have in mind is to create a multipage TIFF from the original picture and add my own picture instead of that frame.
[deleted first part after comment]
I'm working with multi-page TIFFs using LibTIFF.NET; I found many quicks in handling of TIFF using the standard libraries (memory related and also consistent crashes on 16-bit gray scale images).
What is your test image? Have you tried a many-frame tiff (preferably with a large '1' on the first frame, a '2 on the next etc; this could help you to be certain on the frame included in the file.
Another useful diagnosis may be tiffdump utility, as included in LibTiff binaries (also for windows). This will tell you exactly what frames you have.
See Using LibTiff from c# to access tiled tiff images
[Edit] If you want to understand the .NET stuff: I've found a new resource on multi-page tiffs using the standard .NET functionality (although I'll stick with LibTIFF.NET): TheCodeProject : Save images into a multi-page TIFF file... If you download it, the code snippet in Form1.cs function saveMultipage(..) is similar (but still slightly different) than your code. Especially the flushing at the end is done in a differnt way, and the file is deleted before the first frame...
[/Edit]
It seems that this process doesn't change image object but it changes the stream so I should get the memory stream buffer and build another image object:
var buffer=stream.GetBuffer();
using(var newStream=new MemoryStream(buffer))
{
var result=Image.FromStream(newStream);
}
Now result will include all frames.

Categories