I'm working on a Metro application where I need to generate an animated GIF image.
I've found this tutorial, witch seems to be the one and only resource on animated GIFs for Metro apps.
When running this code, an Exception is thrown on the SetPixelData method, telling me that the allocated buffer memory is insufficient (The message is in my OS language even though my Visual Studio environnement is in English, I think it might be relevant).
I've reduced image size (source and output) and frame number, but I still get this error. (I manipulate way bigger images and byte array in the same application).
Any idea where this memory problem can come from ? A problem with my StorageFile maybe ?
I was seeing this exception when the frameWidth\Height being passed into SetPixelData didn't match the pixel data.
I ended up with this example below. I was seeing the exception you mentioned when the dimensions didn't match the pixelData.
I think this is more stable in Windows 8.1 as it doesn't repro on it.
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(sourceStream);
BitmapTransform transform = new BitmapTransform()
{
ScaledHeight = 900,
ScaledWidth = 600
};
PixelDataProvider pixelData = await decoder.GetPixelDataAsync(BitmapPixelFormat.Rgba8,
BitmapAlphaMode.Straight,
transform,
ExifOrientationMode.RespectExifOrientation,
ColorManagementMode.DoNotColorManage);
StorageFile destinationFile = await ApplicationData.Current.LocalFolder.CreateFileAsync(Path.Combine(Database.rootMoviesFoldersPaths, movie.LocalId + ".jpg"));
using (var destinationStream = await destinationFile.OpenAsync(FileAccessMode.ReadWrite))
{
BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, destinationStream);
encoder.SetPixelData(BitmapPixelFormat.Rgba8, BitmapAlphaMode.Premultiplied, 600, 900, 96, 96, pixelData.DetachPixelData());
await encoder.FlushAsync();
movie.HasFolderImage = true;
return true;
}
}
Multiply the buffersize by the bitdepth.
Related
Does anybody know if there is a way to ensure that TextBoxes scale nicely on RenderTargetBitmap?
See my code below, I am attempting to produce an output file of a Canvas with various different elements in it.
Images scale perfectly fine with no loss of quality at all, same with my InkCanvas. But TextBoxes just don't scale well at all.
RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap();
//Produce a PNG output with a pixel size of 5x the onscreen canvas
await renderTargetBitmap.RenderAsync(MaskArea, (int)MaskArea.Width * 5, (int)MaskArea.Height * 5);
var pixelBuffer = await renderTargetBitmap.GetPixelsAsync();
var pixels = pixelBuffer.ToArray();
var displayInformation = DisplayInformation.GetForCurrentView();
var folder = await ApplicationData.Current.LocalFolder.CreateFolderAsync("Print", CreationCollisionOption.OpenIfExists);
var file = await folder.CreateFileAsync("Canvas" + ".png", CreationCollisionOption.ReplaceExisting);
using (var stream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, stream);
encoder.BitmapTransform.InterpolationMode = BitmapInterpolationMode.Cubic;
encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Premultiplied, (uint)renderTargetBitmap.PixelWidth, (uint)renderTargetBitmap.PixelHeight, displayInformation.RawDpiX, displayInformation.RawDpiY, pixels);
await encoder.FlushAsync();
}
I can't really understand why my InkCanvas in particular renders perfectly but yet TextBoxes lose quality.
As a footnote, I'm aware that one way around it would be to manually add the Text to my output file afterwards with Win2D but I just thought I'd check here first in case I'm missing something.
Thanks
Output (You may have to click on the image to see the quality loss)
I am using MediaCapture along with CapturePreview to create a preview stream on a Surface Pro tablet. I am taking photos periodically with a timer using
CapturePhotoToStreamAsync()
Whenever a photo is taken though, the preview stream zooms out slightly as if it is changing the resolution or aspect ratio or something similar.
I found this issue, which sounds exactly the same, but I can't seem to resolve it regardless of the resolutions set.
This is the bit of code I have to grab Bitmap objects from the stream:
using (var randomAccessStream = new InMemoryRandomAccessStream())
{
await mediaCap.CapturePhotoToStreamAsync(imageProps, randomAccessStream);
randomAccessStream.Seek(0);
using (var ioStream = randomAccessStream.AsStream())
{
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.StreamSource = ioStream;
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.EndInit();
bitmapImage.Freeze();
}
}
imageProps is being set to 1280x720, the same resolution as the preview object. This wouldn't be a huge issue if it only happened occasionally, but I need to grab frames frequently (multiple times per second), and it looks very jarring.
Edit:
Something to note is that the issue only occurs on the mentioned Surface Pro tablet (2736x1824 #200%), it doesn't appear to occur on a 1920x1080 screen.
The solution I ended up finding was this change:
From:
await _mediaCaptureObject.InitializeAsync(new MediaCaptureInitializationSettings
{
VideoDeviceId = deviceList?.FirstOrDefault(x => x.Name.Contains("Camera Name"))?.Id,
StreamingCaptureMode = StreamingCaptureMode.Video
});
To:
await _mediaCaptureObject.InitializeAsync(new MediaCaptureInitializationSettings
{
VideoDeviceId = deviceList?.FirstOrDefault(x => x.Name.Contains("Camera Name"))?.Id,
StreamingCaptureMode = StreamingCaptureMode.Video,
PhotoCaptureSource = PhotoCaptureSource.VideoPreview
});
This doesn't really explain the issue I was seeing, since I was setting the ImageEncodingProperties to the same resolution as the stream when capturing the photo. Anyway, the default PhotoCaptureSource is Auto, which must've been using the Photo mode instead of VideoPreview. Once I changed this, the issue stopped appearing.
In my UWP Windows 10 Mobile app, I am attempting to access and manipulate the transparency of individual pixels in the PixelBuffer for a given WriteableBitmap. The issue I'm having is that BitmapDecoder.CreateAsync() is throwing
"The component cannot be found. (Exception from HRESULT:
0x88982F50)".
I have spent WAY too much time searching, refactoring and debugging this to no avail; any hints, direction or help of any kind would be much appreciated.
// img is a WriteableBitmap that contains an image
var stream = img.PixelBuffer.AsStream().AsRandomAccessStream();
BitmapDecoder decoder = null;
try
{
decoder = await BitmapDecoder.CreateAsync(stream);
}
catch(Exception e)
{
// BOOM: The component cannot be found. (Exception from HRESULT: 0x88982F50)
}
// Scale image to appropriate size
BitmapTransform transform = new BitmapTransform()
{
ScaledWidth = Convert.ToUInt32(img.PixelWidth),
ScaledHeight = Convert.ToUInt32(img.PixelHeight)
};
PixelDataProvider pixelData = await decoder.GetPixelDataAsync(
BitmapPixelFormat.Bgra8, // WriteableBitmap uses BGRA format
BitmapAlphaMode.Straight,
transform,
ExifOrientationMode.IgnoreExifOrientation, // This sample ignores Exif orientation
ColorManagementMode.DoNotColorManage
);
// An array containing the decoded image data, which could be modified before being displayed
byte[] pixels = pixelData.DetachPixelData();
UPDATE: In case this helps spark some ideas, I found that if I use the overloaded CreateAsync constructor that supplies a Codec with the stream, it throws a different exception:
Specified cast is not valid.
Guid BitmapEncoderGuid = BitmapEncoder.PngEncoderId;
decoder = await BitmapDecoder.CreateAsync(BitmapEncoderGuid, stream);
It gives the same exception no matter which codec I supply (e.g. Png, Jpeg, GIF, Tiff, Bmp, JpegXR )
I don't understand, why you want to use a BitmapDecoder at all. The pixel data in WriteableBitmap is not encoded in any way. You would need a BitmapDecoder if you were loading the image from a file stream in a particular compression format - this would require you to use the correct codec.
You can just read the pixel data directly from the stream:
byte[] pixels;
using (var stream = img.PixelBuffer.AsStream())
{
pixels = new byte[(uint)stream.Length];
await stream.ReadAsync(pixels, 0, pixels.Length);
}
This will give you a byte array containing 4 bytes for each pixel, corresponding to their R, G, B and A components.
I already can take a print screen from the actual content of my application.
I choose az UIElement (e.g. a grid), and I render it into a bmp file.
But how can I crop this image as i feel?
The code is below works, just the cropping missing. I work for windows 8.1.
public async void SaveVisualElementToFile(UIElement element, StorageFile file)
{
var renderTargetBitmap = new RenderTargetBitmap();
await renderTargetBitmap.RenderAsync(element);
var pixels = await renderTargetBitmap.GetPixelsAsync();
using (IRandomAccessStream stream = await
file.OpenAsync(FileAccessMode.ReadWrite))
{
var encoder = await BitmapEncoder.CreateAsync(
BitmapEncoder.JpegEncoderId, stream);
byte[] bytes = pixels.ToArray();
encoder.SetPixelData(BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Ignore,
(uint)renderTargetBitmap.PixelWidth,
(uint)renderTargetBitmap.PixelHeight,
96, 96, bytes);
await encoder.FlushAsync();
}
}
There are a couple of ways to do this. There's the traditional way as espoused by MSFT themself. You can also use some extensions such as WinRTXamlToolkit and WriteableBitmapEx. The latter two make it quite easy. Check in their source codes on Codeplex for their sample applications, which will have samples for how to use cropping.
I'm working on a WinRT application that will do some image processing and one of the things I want to do is convert some jpgs or pngs to gif. I have something that sort of works. For some of my test jpgs it works others it's a scrambled image that get's output. Just wondering if there was something I was missing. Here is what I have so far
public async static void ConvertToGif(IRandomAccessStream stream)
{
var decoder = await BitmapDecoder.CreateAsync(stream);
var pixels = await decoder.GetPixelDataAsync();
var file = await KnownFolders.PicturesLibrary.CreateFileAsync("test.gif", CreationCollisionOption.ReplaceExisting);
var outStream = await file.OpenAsync(FileAccessMode.ReadWrite);
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.GifEncoderId, outStream);
encoder.SetPixelData(decoder.BitmapPixelFormat, BitmapAlphaMode.Ignore,
decoder.PixelWidth, decoder.PixelHeight,
decoder.DpiX, decoder.DpiY,
pixels.DetachPixelData());
await encoder.FlushAsync();
outStream.Dispose();
}
Smaller jpgs seem to work, but larger ones come out scrambled. Is there another way to achieve this?
Duh, the problem was that I was using PixelWidth/Height and I sholud have been using OrientedPixelWidth/Height.
That seems to have resolved my issue for this.