Im working on a WP7-app where I would like to record video and before the video is saved take a snapshot of the video so that it could be used as a thumbnail picture. The thumbnail picture is temporary save in the isolated storage before it is used. For the camera I use a rectangle to record video and later I want to display the picture on the phone.
The problem is that the picture is displays only a black screen. Even when i tried to save the picture in the media library the picture is also there displayed as black. What can be the cause of this problem and how do i solve it?
I inserted the code below:
Here is the rectangle where you capture the video with.
<Rectangle
x:Name="viewfinderRectangle"
Width="640"
Height="480"
HorizontalAlignment="Left"
Canvas.Left="80"/>
Here is the code for taking the picture:
try
{
String tempJPEG = FOSConstants.TEMP_VIDEO_THUMBNAIL_NAME;
var myStore = IsolatedStorageFile.GetUserStoreForApplication();
if (myStore.FileExists(tempJPEG))
{
myStore.DeleteFile(tempJPEG);
}
IsolatedStorageFileStream myFileStream = myStore.CreateFile(tempJPEG);
WriteableBitmap wb = new WriteableBitmap(viewfinderRectangle, null);
wb.SaveJpeg(myFileStream, wb.PixelWidth, wb.PixelHeight, 0, 85);
myFileStream.Close();
myFileStream.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error saving snapshot", MessageBoxButton.OK);
}
Here is the code for reading the thumbnail picture from the isolated storage:
private BitmapImage GetIsolatedStorageFile(string isolatedStorageFileName)
{
var bimg = new BitmapImage();
using (var store = IsolatedStorageFile.GetUserStoreForApplication())
{
using (var stream = store.OpenFile(isolatedStorageFileName, FileMode.Open, FileAccess.Read))
{
bimg.SetSource(stream);
}
}
return bimg;
}
Here is the image where I want to display my thumbnail in the GUI.
<Image Width="180"
Height="180"
Stretch="Fill"
Margin="24,0,0,0"
Source="{Binding Path=ImageSoruce, Mode=TwoWay}"
HorizontalAlignment="Left"/>
Edit: removed misleading stuff about Invalidate() you dont need to do that.
So you can use the GetPreviewBufferArgb32() method to get what the camera is providing at the moment. This can be copied to your writable bitmap as show below.
using (var myStore = IsolatedStorageFile.GetUserStoreForApplication())
{
if (myStore.FileExists(tempJPEG))
{
myStore.DeleteFile(tempJPEG);
}
IsolatedStorageFileStream file = myStore.CreateFile(tempJPEG);
int[] buf = new int[(int)c.PreviewResolution.Width * (int)c.PreviewResolution.Height];
c.GetPreviewBufferArgb32(buf);
WriteableBitmap wb = new WriteableBitmap((int)c.PreviewResolution.Width, (int)c.PreviewResolution.Height);
Array.Copy(buf, wb.Pixels, buf.Length);
wb.SaveJpeg(file, (int)c.PreviewResolution.Width, (int)c.PreviewResolution.Height, 0, 100);
}
The reason your sample code does not work is that the viewfinder brush is set up on the GPU (I think I can remember why I think it is done there, but I think it is). This means that silverlight does not have access too the raw video and when you render the silverlight element, it is blank (as though it has no background).
Related
There is a Windows program that generates PNG from HTML via WebBrowser.
This PNG must then be inserted into a PDF that is opened in Adobe Acrobat Reader DC as a stamp.
Below is a code that draws a PNG and sends it to the clipboard.
static void webBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
var webBrowser = (WebBrowser)sender;
Bitmap bitmap = new Bitmap(webBrowser.Width, webBrowser.Height, PixelFormat.Format32bppArgb);
webBrowser.DrawToBitmap(bitmap, new Rectangle(0, 0, bitmap.Width, bitmap.Height));
bitmap.MakeTransparent(Color.White);
Clipboard.SetImage(bitmap);
}
The image is clipboard with a gray background, although when saved via bitmap.Save("img.png", ImageFormat.Png); the background is indeed transparent.
using (MemoryStream stream = new MemoryStream())
{
bitmap.Save(stream, ImageFormat.Png);
var data = new DataObject("PNG", stream);
Clipboard.Clear();
Clipboard.SetDataObject(data, true);
}
Tried saving the image to a MemoryStream and sending it to the clipboard as a DataObject. In this case, the clipboard is left empty.
Thanks to Nyerguds, I know that by default the Windows clipboard does not preserve transparency. But due to lack of experience, I can't figure out how to apply it myself.
How can I keep the transparency of the image for later pasting?
I am using EmguCV to get a live stream from a high-resolution webcam. (full HD)
The issue is that there is a significant lag in the video.
I compared with the Windows camera app and my application is much more delayed.
Here is the code snippet I am using to get the live stream and show on the canvas.
I am wondering if I am missing anything important to minimize the lag.
If anybody is experienced, please help me.
void init_camera()
{
m_capture= new VideoCapture(0);
m_capture.ImageGrabbed += ProcessFrame;
}
void ProcessFrame()
{
if (m_capture_in_progress)
return;
m_capture_in_progress = true;
if (m_capture != null && m_capture.Ptr != IntPtr.Zero)
{
m_capture.Retrieve(m_frame, 0);
if (m_frame != null && m_frame.Bitmap != null)
{
if (IsRecording && m_video_writer != null && m_video_writer.IsOpened)
{
try
{
m_video_writer.Write(m_frame);
}
catch (Exception ex)
{
log(ex.Message + "\n" + ex.StackTrace);
}
}
this.Dispatcher.Invoke(() =>
{
using (var stream = new MemoryStream())
{
m_frame.Bitmap.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg);
using (var outstream = new MemoryStream(stream.ToArray()))
{
BitmapImage bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.StreamSource = new MemoryStream(stream.ToArray());
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.EndInit();
ui_canvas.Background = new ImageBrush(bitmap);
}
};
});
}
}
m_capture_in_progress = false;
}
OP is referring some kind of laggs while drawing a camera capture stream from EmguCv into canvas wpf control. OP also states that lagg disappears when streaming with third party software.
This is caused by low performance in OP's code.
After wataching the posted code sample I would suggest the following improvements:
Increasing FPS rate from EmguCV parameters
Maybe your device is supporting higher fps rates, try to increase this value.
Drawing the bitmap over another control like image
As far as I know, drawing a bitmap over a canvas is slower than drawing it over an imagecontrol. A good solution would be to overlap both controls so you can paint the frames over the imageand draw your shapes over the canvasas they are well overlapped.
Cleaning up the rendering method
Keep simple and try to avoid so much control structures when you are inside a critical program block. Specially in program blocks that are executed when an external devices fires an event.
Fixing possible program lock
As far as I can see, you are locking the ProcessFrame event with a bool variable called m_capture_in_progress which is set to true while you are drawing the frame and it is freed after you finish the drawing. This can cause that next incoming frames are not painted because the method is still blocked by the previous frame. This can cause a low performance issue as many frames get lost and not painted.
Use the Image control but set its Source Property to a WriteableBitmap instead of a BitmapImage. Then lock the bitmap, copy the pixel data from your EmguCV Mat to the backbuffer of the WriteableBitmap, call AddDirtyRect method and finally unlock the Bitmap. The final unlock call in combination with the AddDirtyRect will trigger a redraw of the UI image.
Adavantages:
It does not generate a new BitmapImage object each time you want to draw a new frame.
You copy the pixel data only once
Your copy, encode and decode data to often:
// Copies and encodes pixel data to jpeg stream
m_frame.Bitmap.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg);
// Copies jpeg stream
using (var outstream = new MemoryStream(stream.ToArray()))
{
BitmapImage bitmap = new BitmapImage();
bitmap.BeginInit();
//Copies jpeg stream again
bitmap.StreamSource = new MemoryStream(stream.ToArray());
bitmap.CacheOption = BitmapCacheOption.OnLoad;
// Triggers jpeg stream decoding
bitmap.EndInit();
ui_canvas.Background = new ImageBrush(bitmap);
}
I have a part of my application where I am saving photo from CameraCaptureTask. Photos from here in phone's Media Library are fine. I want to save photos also to IsolatedStorage. This is my method for saving:
private void SavePhoto(Stream image, string filename)
{
using (IsolatedStorageFile storageFolder = IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream fileStream = storageFolder.CreateFile(filename))
{
var bitmap = new BitmapImage();
bitmap.SetSource(image);
var wb = new WriteableBitmap(bitmap);
wb.SaveJpeg(fileStream, wb.PixelHeight, wb.PixelWidth, 0, 100);
fileStream.Close();
}
}
}
And this is the part of method displaying photo in another page:
{...
using (IsolatedStorageFile storageFolder = IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream fileStream = storageFolder.OpenFile(_url, FileMode.Open, FileAccess.Read))
{
BitmapImage image = new BitmapImage();
image.SetSource(fileStream);
}
this.fullImage.Source = image;
}
}
XAML code:
<ViewportControl x:Name="viewport"
ManipulationStarted="OnManipulationStarted"
ManipulationDelta="OnManipulationDelta"
ManipulationCompleted="OnManipulationCompleted"
ViewportChanged="viewport_ViewportChanged">
<Canvas x:Name="canvas">
<Image x:Name="fullImage" HorizontalAlignment="Center"
RenderTransformOrigin="0,0"
VerticalAlignment="Center"
CacheMode="BitmapCache"
Stretch="UniformToFill" >
<Image.RenderTransform>
<ScaleTransform x:Name="xform"/>
</Image.RenderTransform>
</Image>
</Canvas>
</ViewportControl>
Image is loaded and displayed but it's weird, it's kind of stretched on one side and narrowed on second side. I'm sorry, I can't take a screenshot since WP 8.1 upgrade, I don't know why. In Windows Phone Emulator it's working fine though.
I am facing a similar scenario. The image, which I am capturing using PhotoCaptureDevice, I am trying to display it in a separate page (which also implements the zoom pan feature), the image is being shown cropped. If I remove the CacheMode = "BitmapCache" attribute from Image, then the image is no longer cropped. However it makes the zoom & pan of the image very jittery.
It seems that there is a size limit (2000 x 2000) of image size in the Windows Phone environment. See this.
Do have a look at the PhotoPage.xaml and PhotoPage.xaml.cs files in the FilterExplorerWP project . It might help you.
I want to do something like that: open an image in the <image> tag and add some other tags on it, for example green rectangle. After that I want to save it like image with rectangle on some part of it. In general user should drag&drop rectangle and could resize it. But the question is: How can I save it? I suppose that I should save parent tag for all of them, for example <grid> or <canvas> but is it possible?
Transform transform = myCanvas.LayoutTransform;
myCanvas.LayoutTransform = null; Size size = new Size(myCanvas.Width,myCanvas.Height); myCanvas.Measure(size);
myCanvas.Arrange(new Rect(size));
RenderTargetBitmap renderBitmap = new RenderTargetBitmap((int)size.Width, (int)size.Height, 96d, 96d,PixelFormats.Pbgra32);
renderBitmap.Render(myCanvas);
using (FileStream outStream = new FileStream(path.LocalPath, FileMode.Create))
{
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(renderBitmap));
encoder.Save(outStream);
}
myCanvas.LayoutTransform = transform;
For a detailed explanation (and the source of the above code), see this blog post:
http://denisvuyka.wordpress.com/2007/12/03/wpf-diagramming-saving-you-canvas-to-image-xps-document-or-raw-xaml/
You can save as PNG, JPG, etc depending on the encoder that you use
I display a photo I took on one of my pages.
I capture the photo in Portrait mode and it works ok.
When I show the picture on my next view, it treats the photo like it was taken in Landscape.
So I need to rotate the picture/image by -90 to correct this.
Here is the relevant code of my .XAML:
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanelx" Grid.Row="1" Margin="0,0,0,0">
</Grid>
And here is the methods where I load the photo and put it into the ContentPanel.:
void loadImage()
{
// The image will be read from isolated storage into the following byte array
byte[] data;
// Read the entire image in one go into a byte array
using (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication())
{
// Open the file - error handling omitted for brevity
// Note: If the image does not exist in isolated storage the following exception will be generated:
// System.IO.IsolatedStorage.IsolatedStorageException was unhandled
// Message=Operation not permitted on IsolatedStorageFileStream
using (IsolatedStorageFileStream isfs = isf.OpenFile("0.jpg", FileMode.Open, FileAccess.Read))
{
// Allocate an array large enough for the entire file
data = new byte[isfs.Length];
// Read the entire file and then close it
isfs.Read(data, 0, data.Length);
isfs.Close();
}
}
// Create memory stream and bitmap
MemoryStream ms = new MemoryStream(data);
BitmapImage bi = new BitmapImage();
// Set bitmap source to memory stream
bi.SetSource(ms);
// Create an image UI element – Note: this could be declared in the XAML instead
Image image = new Image();
// Set size of image to bitmap size for this demonstration
image.Height = bi.PixelHeight;
image.Width = bi.PixelWidth;
// Assign the bitmap image to the image’s source
image.Source = bi;
// Add the image to the grid in order to display the bit map
ContentPanelx.Children.Add(image);
}
}
I am thinking on a simple rotate on the image after I've loaded this. I can do this in iOS, but my C# is skills are worse than bad.
Can anybody advise on this?
If the image is declared in xaml you can rotate it like this:
//XAML
<Image.RenderTransform>
<RotateTransform Angle="90" />
</Image.RenderTransform>
Same thing can be done thru c# also. If you always rotate the image , then doint it in xaml is the better optioin
//C#
((RotateTransform)image.RenderTransform).Angle = angle;
Please try this one:
RotateTransform rt = new RotateTransform();
rt.Angle = 90;
image.RenderTransform = rt;
You can create a RotateTransform object to use for the image's RenderTransform property. This will cause WPF to rotate the Image control when rendered.
If you want to rotate the image about it's center you will also need to set the rotation origin, as shown below:
RotateTransform rt = new RotateTransform();
rt.Angle = 90;
image.RenderTransform = rt;
image.RenderTransformOrigin = new Point(0.5, 0.5);