I want to make an application which captures images using the camera and stores it in the isolated storage of the phone.How ever, i am able to store 7 images in each run(i.e. each time the emulator is activated) and for the eight image that i capture and save, i get an out of memory exception.If I have to store more images in the isolated storage, i have to stop debugging and restart debugging.I am new to wp7 development.I am using the emulator for debugging.Please help
Stream doc_photo;
List<document> doc_list = new List<document>();
document newDoc = new document();
public Page2()
{
InitializeComponent();
}
private void captureDocumentImage(object sender, RoutedEventArgs e)
{
ShowCameraCaptureTask();
}
private void ShowCameraCaptureTask()
{
CameraCaptureTask photoCameraCapture = new CameraCaptureTask();
photoCameraCapture = new CameraCaptureTask();
photoCameraCapture.Completed += new EventHandler<PhotoResult>photoCameraCapture_Completed);
photoCameraCapture.Show();
}
void photoCameraCapture_Completed(object sender, PhotoResult e)
{
if (e.TaskResult == TaskResult.OK)
{
capturedImage.Source = PictureDecoder.DecodeJpeg(e.ChosenPhoto);
doc_photo = e.ChosenPhoto;
}
}
private void SaveToIsolatedStorage(Stream imageStream, string fileName)
{
using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
if (myIsolatedStorage.FileExists(fileName))
{
myIsolatedStorage.DeleteFile(fileName);
}
IsolatedStorageFileStream fileStream = myIsolatedStorage.CreateFile(fileName);
BitmapImage bitmap = new BitmapImage();
bitmap.SetSource(imageStream);
try
{
WriteableBitmap wb = new WriteableBitmap(bitmap);
wb.SaveJpeg(fileStream, wb.PixelWidth, wb.PixelHeight, 0, 85);
fileStream.Close();
}
catch (OutOfMemoryException e1)
{
MessageBox.Show("memory exceeded");
}
}
}
private void save_buttonclicked(object sender, RoutedEventArgs e)
{
if (namebox.Text != "" && doc_photo!=null)
{
newDoc.doc_name = namebox.Text;
IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication();
if(!myIsolatedStorage.DirectoryExists(App.current_panorama_page))
{
myIsolatedStorage.CreateDirectory(App.current_panorama_page);
}
newDoc.photo = App.current_panorama_page + "/" + namebox.Text + ".jpg";//
SaveToIsolatedStorage(doc_photo, newDoc.photo);
doc_list.Add(newDoc);
NavigationService.Navigate(new Uri("/MainPage.xaml", UriKind.Relative));
}
else
{
if (namebox.Text == "")
{
MessageBox.Show("Enter the name");
}
else if (doc_photo == null)
{
MessageBox.Show("Capture an Image");
}
}
}
you are saving the bitmap to 'doc_list', not just the URL, so the phone will have each image you capture in memory. You should probably go for a solution where the images are referenced in the UI using regular image controls and the 'isostore://' URLs.
EDIT:
In the example below I use an ObservableCollection for storing IsoImageWrappers. The latter class handles the connection to isolated storage, by instantiating an isolated file stream with the URI given in constructor.
The ObservableCollection will notify the WP7 framework when new images are added. Storing images is almost as your original proposal.
The list box binding is:
<ListBox Grid.Row="0" Height="495" Margin="0" Name="listBox1" Width="460" >
<ListBox.ItemTemplate>
<DataTemplate>
<Image Source="{Binding Source}" Width="Auto" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
and the code with ugly inline of helper classes etc:
using System;
using System.Collections.ObjectModel;
using System.IO;
using System.IO.IsolatedStorage;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Tasks;
namespace WP7Photo
{
public partial class MainPage : PhoneApplicationPage
{
public class IsoImageWrapper
{
public string Uri { get; set; }
public ImageSource Source
{
get
{
IsolatedStorageFile isostore = IsolatedStorageFile.GetUserStoreForApplication();
var bmi = new BitmapImage();
bmi.SetSource(isostore.OpenFile(Uri, FileMode.Open, FileAccess.Read));
return bmi;
}
}
}
public ObservableCollection<IsoImageWrapper> Images { get; set; }
// Constructor
public MainPage()
{
InitializeComponent();
Images = new ObservableCollection<IsoImageWrapper>();
listBox1.ItemsSource = Images;
}
private void Button1Click(object sender, RoutedEventArgs e)
{
var cameraTask = new CameraCaptureTask();
cameraTask.Completed += new EventHandler<PhotoResult>(cameraTask_Completed);
cameraTask.Show();
}
void cameraTask_Completed(object sender, PhotoResult e)
{
if (e.TaskResult != TaskResult.OK)
{
return;
}
StorePhoto(e);
}
private void StorePhoto(PhotoResult photo)
{
IsolatedStorageFile isostore = IsolatedStorageFile.GetUserStoreForApplication();
if (!isostore.DirectoryExists("photos"))
{
isostore.CreateDirectory("photos");
}
var filename = "photos/" + System.IO.Path.GetFileName(photo.OriginalFileName);
if (isostore.FileExists(filename)) { isostore.DeleteFile(filename);}
using (var isoStream = isostore.CreateFile(filename))
{
photo.ChosenPhoto.CopyTo(isoStream);
}
Images.Add(new IsoImageWrapper {Uri = filename});
}
}
}
Related
I'm trying to create an SVG file from some shape objects(path geometries, ellipses etc.) drawn on XAML canvas controls (the canvases are rendered on top of each other inside grid controls). It looks like Win2D can provide the classes to generate the SVG file, but I'm struggling to figure out how to populate the CanvasSvgDocument class with the shapes.
This is the only partial example I've found, but the answer seems to include a conversion to XML strings to load into the CanvasSvgDocument which seems like doing the same task twice (as SVG files are XML). Is anybody able to provide an example of how I might do this?
My current best guess of what the resulting code might look like is:
using Microsoft.Graphics.Canvas;
using Microsoft.Graphics.Canvas.Svg;
using Microsoft.Graphics.Canvas.UI.Xaml;
using System;
using System.Threading.Tasks;
using Windows.Storage.Streams;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Shapes;
namespace MyApp
{
public class ExportSVG
{
private CanvasSvgDocument SVG { get; } = new(new CanvasDevice());
public async Task SaveASync(IRandomAccessStream stream) => await SVG.SaveAsync(stream);
public void AddCanvases(UIElement element)
{
if (element is Grid grid)
{
foreach (UIElement child in grid.Children)
{
AddCanvases(child);
}
}
else if (element is Canvas canvas)
{
AddCanvas(canvas);
}
}
public void AddCanvas(Canvas canvas)
{
foreach (UIElement element in canvas.Children)
{
if (element is Path path)
{
if (path.Data is PathGeometry pathGeometry)
{
foreach (PathFigure pathFigure in pathGeometry.Figures)
{
// Add path to SVG
}
}
else if (path.Data is EllipseGeometry ellipseGeometry)
{
// Add ellipse to SVG
}
}
else if (element is TextBlock textBlock)
{
// add text to SVG
}
}
}
}
}
You could use CanvasGeometry.CreateInk convert the ink strokes into geometry and use the relevant methods under the CanvasGeometry namespace to get the path, then write a custom class to read the parse path. Finally, the generated CanvasSvgDocument object is used to save the stream containing the svg content.
Please refer to the following sample to do these steps. (Note: download Win2D.uwp package)
XAML code:
<Page
x:Class="CanvasToSVG.MainPage"
…
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid>
<StackPanel>
<InkCanvas x:Name="MyInkConntrol" Height="500">
</InkCanvas>
<InkToolbar Grid.Row="1" TargetInkCanvas="{x:Bind MyInkConntrol}" HorizontalAlignment="Left">
<InkToolbarCustomToolButton Click="save">
<SymbolIcon Symbol="Save" />
</InkToolbarCustomToolButton>
</InkToolbar>
<Line Stroke="Black"/>
<Image Name="ImageControl"></Image>
</StackPanel>
</Grid>
</Page>
Code behind:
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
MyInkConntrol.InkPresenter.InputDeviceTypes= CoreInputDeviceTypes.Mouse |CoreInputDeviceTypes.Pen |
CoreInputDeviceTypes.Touch;
MyInkConntrol.InkPresenter.StrokesCollected += InkPresenter_StrokesCollected;
MyInkConntrol.InkPresenter.StrokesErased += InkPresenter_StrokesErased;
}
private async void InkPresenter_StrokesErased(Windows.UI.Input.Inking.InkPresenter sender, Windows.UI.Input.Inking.InkStrokesErasedEventArgs args)
{
await RenderSvg();
}
private async void InkPresenter_StrokesCollected(Windows.UI.Input.Inking.InkPresenter sender, Windows.UI.Input.Inking.InkStrokesCollectedEventArgs args)
{
await RenderSvg();
}
public async Task RenderSvg()
{
using (var stream=new InMemoryRandomAccessStream())
{
await RenderSvg(stream);
var image= new SvgImageSource();
await image.SetSourceAsync(stream);
ImageControl.Source = image;
}
}
public async Task RenderSvg(IRandomAccessStream randomAccessStream)
{
var sharedDevice = CanvasDevice.GetSharedDevice();
using (var offscreen = new CanvasRenderTarget(sharedDevice, (float)MyInkConntrol.RenderSize.Width, (float)MyInkConntrol.RenderSize.Height, 96))
{
using (var session = offscreen.CreateDrawingSession())
{
var svgDocument = new CanvasSvgDocument(sharedDevice);
svgDocument.Root.SetStringAttribute("viewBox", $"0 0 {MyInkConntrol.RenderSize.Width} {MyInkConntrol.RenderSize.Height}");
foreach (var stroke in MyInkConntrol.InkPresenter.StrokeContainer.GetStrokes())
{
var canvasGeometry = CanvasGeometry.CreateInk(session, new[] { stroke }).Outline();
var pathReceiver = new CanvasGeometryToSvgPathReader();
canvasGeometry.SendPathTo(pathReceiver);
var element = svgDocument.Root.CreateAndAppendNamedChildElement("path");
element.SetStringAttribute("d", pathReceiver.Path);
var color = stroke.DrawingAttributes.Color;
element.SetColorAttribute("fill", color);
}
await svgDocument.SaveAsync(randomAccessStream);
}
}
}
private async void save(object sender, RoutedEventArgs e)
{
FileSavePicker savePicker = new FileSavePicker();
savePicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
savePicker.FileTypeChoices.Add("svg file", new List<string>() { ".svg" });
savePicker.SuggestedFileName = "NewSvgfile1";
var file = await savePicker.PickSaveFileAsync();
if (file != null)
{
using (var writeStream = (await file.OpenStreamForWriteAsync()).AsRandomAccessStream())
{
await RenderSvg(writeStream);
await writeStream.FlushAsync();
}
}
}
}
Custom class:
public class CanvasGeometryToSvgPathReader: ICanvasPathReceiver
{
private readonly Vector2 _ratio;
private List<string> Parts { get; }
public string Path => string.Join(" ", Parts);
public CanvasGeometryToSvgPathReader() : this(Vector2.One)
{ }
public CanvasGeometryToSvgPathReader(Vector2 ratio)
{
_ratio = ratio;
Parts = new List<string>();
}
public void BeginFigure(Vector2 startPoint, CanvasFigureFill figureFill)
{
Parts.Add($"M{startPoint.X / _ratio.X} {startPoint.Y / _ratio.Y}");
}
public void AddArc(Vector2 endPoint, float radiusX, float radiusY, float rotationAngle, CanvasSweepDirection sweepDirection, CanvasArcSize arcSize)
{
}
public void AddCubicBezier(Vector2 controlPoint1, Vector2 controlPoint2, Vector2 endPoint)
{
Parts.Add($"C{controlPoint1.X / _ratio.X},{controlPoint1.Y / _ratio.Y} {controlPoint2.X / _ratio.X},{controlPoint2.Y / _ratio.Y} {endPoint.X / _ratio.X},{endPoint.Y / _ratio.Y}");
}
public void AddLine(Vector2 endPoint)
{
Parts.Add($"L {endPoint.X / _ratio.X} {endPoint.Y / _ratio.Y}");
}
public void AddQuadraticBezier(Vector2 controlPoint, Vector2 endPoint)
{
//
}
public void SetFilledRegionDetermination(CanvasFilledRegionDetermination filledRegionDetermination)
{
//
}
public void SetSegmentOptions(CanvasFigureSegmentOptions figureSegmentOptions)
{
//
}
public void EndFigure(CanvasFigureLoop figureLoop)
{
Parts.Add("Z");
}
}
In the end I was able to use the XmlWriter class to write my own canvas-to-svg converter. Using the example in the question:
using Microsoft.Graphics.Canvas;
using Microsoft.Graphics.Canvas.Svg;
using Microsoft.Graphics.Canvas.UI.Xaml;
using System;
using System.Xml;
using System.Threading.Tasks;
using Windows.Storage.Streams;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Shapes;
namespace MyApp
{
public class ExportSVG
{
private XmlWriter Writer { get; }
public SVGWriter(System.IO.Stream stream)
{
Writer = XmlWriter.Create(stream, new XmlWriterSettings()
{
Indent = true,
});
Writer.WriteStartElement("svg", "http://www.w3.org/2000/svg");
Write("version", "1.1");
}
public void AddCanvases(UIElement element)
{
if (element is Grid grid)
{
foreach (UIElement child in grid.Children)
{
AddCanvases(child);
}
}
else if (element is Canvas canvas)
{
AddCanvas(canvas);
}
}
public void AddCanvas(Canvas canvas)
{
foreach (UIElement element in canvas.Children)
{
if (element is Path path)
{
else if (path.Data is EllipseGeometry ellipseGeometry)
{
Writer.WriteStartElement("ellipse");
Write("stroke", ellipseGeometry.Stroke);
Write("stroke-width", ellipseGeometry.StrokeThickness);
Write("cx", ellipseGeometry.Center.X);
Write("cy", ellipseGeometry.Center.Y);
Write("rx", ellipseGeometry.RadiusX);
Write("ry", ellipseGeometry.RadiusY);
Writer.WriteEndElement();
}
}
else if (element is TextBlock textBlock)
{
Writer.WriteStartElement("text");
Write("x", Canvas.GetLeft(textBlock));
Write("y", Canvas.GetTop(textBlock) + textBlock.ActualHeight);
Write("font-family", textBlock.FontFamily.Source);
Write("font-size", $"{textBlock.FontSize}px");
Writer.WriteString(textBlock.Text);
Writer.WriteEndElement();
}
}
}
private void Write(string name, string value)
{
Writer.WriteAttributeString(name, value);
}
private void Write(string name, double value)
{
Write(name, ((float)value).ToString());
}
public void Dispose()
{
Writer.WriteEndElement();
Writer.Close();
Writer.Dispose();
}
}
}
I've some hard time trying to display images in my UWP App.
My images are located in the Images library.
The question is:
How to show jpg in the Image Xaml control on a UWP, that is not in the projects "Assets"?
So far using Binding, I’ve
Try to set Image.Source to the full path with no success, image control remains blank. (for file access retriction a guess)
Try using setting BitMapImage to the Image.Source property with no success, image control remains blank. (for file access retriction a guess)
Try to assign FileStorage class to the Image.Source property with no success, image control remains blank.
Try to load the image file in a stream and load the stream in the BitmapImage, but there I’ve threading issues. More about this below.
About the threading issue, I’ve come to two issues for now.
When loading the file/stream:
var file = File.ReadAllBytes(_currentImagePath);
I get
System.InvalidOperationException: 'Synchronous operations should not be performed on the UI thread. Consider wrapping this method in Task.Run.'
When using Task.Run on any manner I get an exception when trying to set the Bitmap source
The application called an interface that was marshalled for a different thread. (Exception from HRESULT: 0x8001010E (RPC_E_WRONG_THREAD))
var bitmap = new BitmapImage();
return await Task.Run(async () =>
{
var file = File.ReadAllBytes(_currentImagePath);
using (var stream = new InMemoryRandomAccessStream())
{
await stream.WriteAsync(file.AsBuffer());
stream.Seek(0);
await bitmap.SetSourceAsync(stream); // **Exception here**
return bitmap;
}
});
Here the full source code:
namespace App1.Images
{
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading.Tasks;
using Windows.Storage;
using Windows.Storage.Streams;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Media.Imaging;
using App1.Annotations;
public class ImagesLibrairies : INotifyPropertyChanged
{
private readonly HashSet<Image> _images;
private readonly string _fileTypes;
private readonly HashSet<Image> _preferrednessFiles;
private readonly DispatcherTimer _timer;
private ulong _minFileSize = 5 * 1024; // 5k in bytes
private ulong _maxFileSize = 1024 * 1024 * 20; //20 MBytes
private int _imageIndex = 0;
public ImagesLibrairies()
{
_preferrednessFiles = new HashSet<Image>();
_fileTypes = "*.jpg;*.jpeg;*.bmp;*.tif"; // ignore *.ico;*.png;*.svg;*.gif
_images = new HashSet<Image>();
_timer = new DispatcherTimer { Interval = new TimeSpan(0, 0, 0, 5) };
_timer.Tick += _timer_Tick;
}
private Uri _currentImage;
public Uri CurrentImage
{
get => _currentImage;
private set
{
_currentImage = value;
OnPropertyChanged(nameof(CurrentImage));
OnPropertyChanged(nameof(Image));
}
}
public async Task<BitmapImage> GetBitmapImage()
{
var bitmap = new BitmapImage();
return await Task.Run(async () =>
{
var file = File.ReadAllBytes(_currentImagePath);
using (var stream = new InMemoryRandomAccessStream())
{
await stream.WriteAsync(file.AsBuffer());
stream.Seek(0);
await bitmap.SetSourceAsync(stream);
return bitmap;
}
});
}
public BitmapImage Image
{
get
{
if (!string.IsNullOrEmpty(_currentImagePath))
return GetBitmapImage().Result;
return null;
}
}
private string _currentImagePath;
public string CurrentImagePath
{
get => _currentImagePath;
set
{
_currentImagePath = value;
OnPropertyChanged(nameof(CurrentImagePath));
CurrentImage = new Uri(value);
}
}
public object CurrentStorageFile { get; set; }
private void _timer_Tick(object sender, object e)
{
SetNext();
}
public async Task ScanLibrairies()
{
var picturesFolder = KnownFolders.PicturesLibrary;
var files = await picturesFolder.GetFilesAsync();
foreach (var file in files)
{
Debug.WriteLine(file.Name + ", " + file.DateCreated);
if (_images.Count >= int.MaxValue)
return;
var prop = await file.GetBasicPropertiesAsync();
var imageLocation = new Image
{
StorageFile = file,
Properties = prop
};
if (imageLocation.Properties.Size < _minFileSize || imageLocation.Properties.Size > _maxFileSize)
continue;
if (_preferrednessFiles.Any(o => o.Equals(imageLocation) && o.Preferredness == Preferredness.No))
continue;
_images.Add(imageLocation);
}
}
public void SetNext()
{
if (_images == null || !_images.Any())
{
return;
}
_imageIndex++;
var image = _images.Skip(_imageIndex).FirstOrDefault();
if (image != null)
{
Debug.WriteLine($"Displaying: {image.StorageFile.Path}");
}
CurrentImagePath = image?.StorageFile.Path;
CurrentImage = new Uri(CurrentImagePath);
}
public void SetPrevious()
{
if (_images == null || !_images.Any())
return;
_imageIndex--;
var image = _images.Skip(_imageIndex).FirstOrDefault();
CurrentImagePath = image?.StorageFile.Path;
}
public void LikeThisPicture(Image picture)
{
var pic = _preferrednessFiles.FirstOrDefault(o => o.Equals(picture));
if (pic == null)
{
picture.Preferredness = Preferredness.Very;
_preferrednessFiles.Add(picture);
return;
}
pic.Preferredness = Preferredness.Very;
}
public void DislikeThisPicture(Image picture)
{
var pic = _preferrednessFiles.FirstOrDefault(o => o.Equals(picture));
if (pic == null)
{
picture.Preferredness = Preferredness.No;
_preferrednessFiles.Add(picture);
return;
}
pic.Preferredness = Preferredness.No;
}
public void StartAsync()
{
ScanLibrairies();
_timer.Start();
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Here the xaml markup
<Page.DataContext>
<images:ImagesLibrairies/>
</Page.DataContext>
<Grid >
<!--Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">-->
<Image Stretch="UniformToFill" Margin="15">
<Image.Source>
<BitmapImage UriSource="{Binding Image}"></BitmapImage>
<!--<BitmapImage UriSource="{Binding CurrentImagePath}"></BitmapImage>-->
<!--<BitmapImage UriSource="D:\Utilisateurs\hugod\OneDrive\Images\jouets\20180106_132041.jpg"></BitmapImage>-->
<!--<BitmapImage UriSource="Assets/Black-And-White-Wall-Brick-Texture-Shadow-WallpapersByte-com-3840x2160.jpg"></BitmapImage>-->
<!--<BitmapImage UriSource="{Binding CurrentStorageFile}"></BitmapImage>-->
</Image.Source>
</Image>
</Grid>
Raymond is right!
CurrentImage = new BitmapImage();
await CurrentImage.SetSourceAsync(await image.StorageFile.OpenAsync(FileAccessMode.Read));
A goody for Raymond!
I found this code on StackOverflow. & This code works great for converting a website to image. However, instead of navigating to a new URL, can this code be modified to capture the current website?
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Threading;
using System.Windows.Forms;
public class WebsiteToImage
{
private Bitmap m_Bitmap;
private string m_Url;
private string m_FileName = string.Empty;
public WebsiteToImage(string url)
{
// Without file
m_Url = url;
}
public WebsiteToImage(string url, string fileName)
{
// With file
m_Url = url;
m_FileName = fileName;
}
public Bitmap Generate()
{
// Thread
var m_thread = new Thread(_Generate);
m_thread.SetApartmentState(ApartmentState.STA);
m_thread.Start();
m_thread.Join();
return m_Bitmap;
}
private void _Generate()
{
var browser = new WebBrowser { ScrollBarsEnabled = false };
browser.Navigate(m_Url);
browser.DocumentCompleted += WebBrowser_DocumentCompleted;
while (browser.ReadyState != WebBrowserReadyState.Complete)
{
Application.DoEvents();
}
browser.Dispose();
}
private void WebBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
// Capture
var browser = (WebBrowser)sender;
browser.ClientSize = new Size(browser.Document.Body.ScrollRectangle.Width, browser.Document.Body.ScrollRectangle.Bottom);
browser.ScrollBarsEnabled = false;
m_Bitmap = new Bitmap(browser.Document.Body.ScrollRectangle.Width, browser.Document.Body.ScrollRectangle.Bottom);
browser.BringToFront();
browser.DrawToBitmap(m_Bitmap, browser.Bounds);
// Save as file?
if (m_FileName.Length > 0)
{
// Save
m_Bitmap.SaveJPG100(m_FileName);
}
}
}
public static class BitmapExtensions
{
public static void SaveJPG100(this Bitmap bmp, string filename)
{
var encoderParameters = new EncoderParameters(1);
encoderParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L);
bmp.Save(filename, GetEncoder(ImageFormat.Jpeg), encoderParameters);
}
public static void SaveJPG100(this Bitmap bmp, Stream stream)
{
var encoderParameters = new EncoderParameters(1);
encoderParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L);
bmp.Save(stream, GetEncoder(ImageFormat.Jpeg), encoderParameters);
}
public static ImageCodecInfo GetEncoder(ImageFormat format)
{
var codecs = ImageCodecInfo.GetImageDecoders();
foreach (var codec in codecs)
{
if (codec.FormatID == format.Guid)
{
return codec;
}
}
// Return
return null;
}
}
i am currently learning on QR code webcam decoder. i have taken an example from https://zxingnet.svn.codeplex.com/svn/trunk/Clients/AForgeDemo/ and have succesfully build it without error. however when i run it with my webcam connected, no input or it wont switch on the webcam. based on my understanding, the webcam would be switch on when user select it at combobox. well, since there is no error at build, i cant pinpoint what went wrong. i have also taken a look at a project which switch on the webcam when user press a button and i plan to implement it to the current project. i have already insert the button but i do not know what should i program at the button to switch on the webcam instead on having to choose at combobox
would someone kindly advise or guide me through it.
below is the main program, and 2 class
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using AForge.Video;
using ZXing;
using System.Threading;
namespace AForgeDemo
{
public partial class AForgeDemoForm : Form
{
private struct Device
{
public int Index;
public string Name;
public override string ToString()
{
return Name;
}
}
private readonly CameraDevices camDevices;
private Bitmap currentBitmapForDecoding;
private readonly Thread decodingThread;
private Result currentResult;
private readonly Pen resultRectPen;
public AForgeDemoForm()
{
InitializeComponent();
camDevices = new CameraDevices();
decodingThread = new Thread(DecodeBarcode);
decodingThread.Start();
pictureBox1.Paint += pictureBox1_Paint;
resultRectPen = new Pen(Color.Green, 10);
}
void pictureBox1_Paint(object sender, PaintEventArgs e)
{
if (currentResult == null)
return;
if (currentResult.ResultPoints != null && currentResult.ResultPoints.Length > 0)
{
var resultPoints = currentResult.ResultPoints;
var rect = new Rectangle((int)resultPoints[0].X, (int)resultPoints[0].Y, 1, 1);
foreach (var point in resultPoints)
{
if (point.X < rect.Left)
rect = new Rectangle((int)point.X, rect.Y, rect.Width + rect.X - (int)point.X, rect.Height);
if (point.X > rect.Right)
rect = new Rectangle(rect.X, rect.Y, rect.Width + (int)point.X - rect.X, rect.Height);
if (point.Y < rect.Top)
rect = new Rectangle(rect.X, (int)point.Y, rect.Width, rect.Height + rect.Y - (int)point.Y);
if (point.Y > rect.Bottom)
rect = new Rectangle(rect.X, rect.Y, rect.Width, rect.Height + (int)point.Y - rect.Y);
}
using (var g = pictureBox1.CreateGraphics())
{
g.DrawRectangle(resultRectPen, rect);
}
}
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
LoadDevicesToCombobox();
}
protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
{
base.OnClosing(e);
if (!e.Cancel)
{
decodingThread.Abort();
if (camDevices.Current != null)
{
camDevices.Current.NewFrame -= Current_NewFrame;
if (camDevices.Current.IsRunning)
{
camDevices.Current.SignalToStop();
}
}
}
}
private void LoadDevicesToCombobox()
{
cmbDevice.Items.Clear();
for (var index = 0; index < camDevices.Devices.Count; index++)
{
cmbDevice.Items.Add(new Device { Index = index, Name = camDevices.Devices[index].Name });
}
}
private void cmbDevice_SelectedIndexChanged(object sender, EventArgs e)
{
if (camDevices.Current != null)
{
camDevices.Current.NewFrame -= Current_NewFrame;
if (camDevices.Current.IsRunning)
{
camDevices.Current.SignalToStop();
}
}
camDevices.SelectCamera(((Device)(cmbDevice.SelectedItem)).Index);
camDevices.Current.NewFrame += Current_NewFrame;
camDevices.Current.Start();
}
private void Current_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
if (IsDisposed)
{
return;
}
try
{
if (currentBitmapForDecoding == null)
{
currentBitmapForDecoding = (Bitmap)eventArgs.Frame.Clone();
}
Invoke(new Action<Bitmap>(ShowFrame), eventArgs.Frame.Clone());
}
catch (ObjectDisposedException)
{
// not sure, why....
}
}
private void ShowFrame(Bitmap frame)
{
if (pictureBox1.Width < frame.Width)
{
pictureBox1.Width = frame.Width;
}
if (pictureBox1.Height < frame.Height)
{
pictureBox1.Height = frame.Height;
}
pictureBox1.Image = frame;
}
private void DecodeBarcode()
{
var reader = new BarcodeReader();
while (true)
{
if (currentBitmapForDecoding != null)
{
var result = reader.Decode(currentBitmapForDecoding);
if (result != null)
{
Invoke(new Action<Result>(ShowResult), result);
}
currentBitmapForDecoding.Dispose();
currentBitmapForDecoding = null;
}
Thread.Sleep(200);
}
}
private void ShowResult(Result result)
{
currentResult = result;
txtBarcodeFormat.Text = result.BarcodeFormat.ToString();
txtContent.Text = result.Text;
}
private void button1_Click(object sender, EventArgs e)
{
}
}
}
the class for cameradevice
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AForge.Video.DirectShow;
namespace AForgeDemo
{
internal class CameraDevices
{
public FilterInfoCollection Devices { get; private set; }
public VideoCaptureDevice Current { get; private set; }
public CameraDevices()
{
Devices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
}
public void SelectCamera(int index)
{
if (index >= Devices.Count)
{
throw new ArgumentOutOfRangeException("index");
}
Current = new VideoCaptureDevice(Devices[index].MonikerString);
}
}
}
again, i kindly ask for anybody help on what i shall put at the button command to activate the webcam directly instead of choosing from combobox
thanks a million
The code which you need for your event handler behind the button is similar to the code within the method cmbDevice_SelectedIndexChanged.
I think it should look like the following
// select the first available camera and start capturing
camDevices.SelectCamera(0);
camDevices.Current.NewFrame += Current_NewFrame;
camDevices.Current.Start();
But I think the main challenge is to find out why the original example doesn't work as expected. It makes no difference if the same code is called in the handler of the combobox or in the handler of the button.
I am creating an application for WP7.1 with Phonegap in which I have to download a video and save it in Isolated Storage.
Now while reading that video, for the first time I can read it correctly, but after that I am not able to read the stream. This exception occurs every I try to read that video after I have read it once : Operation not permitted on IsolatedStorageFileStream.
Taken the code from : How to play embedded video in WP7 - Phonegap?
and added Pause and Stop functionality.
using System;
using System.IO;
using System.IO.IsolatedStorage;
using System.Runtime.Serialization;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Phone.Controls;
using WP7CordovaClassLib.Cordova.JSON;
namespace WP7CordovaClassLib.Cordova.Commands
{
public class Video : BaseCommand
{
/// <summary>
/// Video player object
/// </summary>
private MediaElement _player;
Grid grid;
[DataContract]
public class VideoOptions
{
/// <summary>
/// Path to video file
/// </summary>
[DataMember(Name = "src")]
public string Src { get; set; }
}
public void Play(string args)
{
VideoOptions options = JsonHelper.Deserialize<VideoOptions>(args);
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
try
{
_Play(options.Src);
DispatchCommandResult(new PluginResult(PluginResult.Status.OK));
}
catch (Exception e)
{
DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
GoBack();
}
});
}
private void _Play(string filePath)
{
if (_player != null)
{
if (_player.CurrentState == System.Windows.Media.MediaElementState.Paused)
{
_player.Play();
}
}
else
{
// this.player is a MediaElement, it must be added to the visual tree in order to play
PhoneApplicationFrame frame = Application.Current.RootVisual as PhoneApplicationFrame;
if (frame != null)
{
PhoneApplicationPage page = frame.Content as PhoneApplicationPage;
if (page != null)
{
grid = page.FindName("VideoPanel") as Grid;
if (grid != null && _player == null)
{
_player = new MediaElement();
grid.Children.Add(this._player);
grid.Visibility = Visibility.Visible;
_player.Visibility = Visibility.Visible;
_player.MediaEnded += new RoutedEventHandler(_player_MediaEnded);
}
}
}
Uri uri = new Uri(filePath, UriKind.RelativeOrAbsolute);
if (uri.IsAbsoluteUri)
{
_player.Source = uri;
}
else
{
using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
{
if (isoFile.FileExists(filePath))
{
**using (IsolatedStorageFileStream stream =
new IsolatedStorageFileStream(filePath, FileMode.Open, isoFile))
{
_player.SetSource(stream);
stream.Close();
}
}
else
{
throw new ArgumentException("Source doesn't exist");
}
}
}
_player.Play();
}
}
void _player_MediaEnded(object sender, RoutedEventArgs e)
{
GoBack();
}
public void Pause(string args)
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
try
{
_Pause(args);
DispatchCommandResult(new PluginResult(PluginResult.Status.OK));
}
catch (Exception e)
{
DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
}
});
}
private void _Pause(string filePath)
{
if (_player != null)
{
if (_player.CurrentState == System.Windows.Media.MediaElementState.Playing)
{
_player.Pause();
}
}
}
public void Stop(string args)
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
try
{
_Stop(args);
DispatchCommandResult(new PluginResult(PluginResult.Status.OK));
}
catch (Exception e)
{
DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
}
});
}
private void _Stop(string filePath)
{
GoBack();
}
private void GoBack()
{
if (_player != null)
{
if (_player.CurrentState == System.Windows.Media.MediaElementState.Playing
|| _player.CurrentState == System.Windows.Media.MediaElementState.Paused)
{
_player.Stop();
}
_player.Visibility = Visibility.Collapsed;
_player = null;
}
if (grid != null)
{
grid.Visibility = Visibility.Collapsed;
}
}
}
}
** The exception (Operation not permitted on IsolatedStorageFileStream.) occurs at _Play function while reading the file (Please see ** in code above). First time it runs perfectly and when I come to read the file second time it gives Exception.
What might be the problem?
Is I am doing something wrong?
It sounds like the file is still open from the previous read. If this is the case, you need to specify the fileAccess and fileShare to allow it to be opened by another thread:
using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, isoFile)
I solved this problem by just setting the source property of the MediaElement to null before navigating back. So, when i come back to play the same video, the MediaElement source is free for it.
Edited the GoBack Function to :
private void GoBack()
{
// see whole code from original question.................
_player.Visibility = Visibility.Collapsed;
_player.Source = null; // added this line
_player = null;
//..................
}
Thanks All.