I want to take a screen shot from my web-based Silverlight 5 application and save it on disk, what are my options? I've searched a lot but found nothing useful.
This appears to capture and save it to disk
Capture
// create a WriteableBitmap
WriteableBitmap bitmap = new WriteableBitmap(
(int)this.LayoutRoot.ActualWidth,
(int)this.LayoutRoot.ActualHeight);
// render the visual element to the WriteableBitmap
bitmap.Render(this.LayoutRoot, this.transform);
// request an redraw of the bitmap
bitmap.Invalidate();
Save
private void ThumbnailClicked(object sender, MouseButtonEventArgs e)
{
// pause the capture timer
this.timer.Stop();
try
{
// locate the WriteableBitmap source for the clicked image
WriteableBitmap bitmap = ((Image)sender).Source as WriteableBitmap;
if (null == bitmap)
{
MessageBox.Show("Nothing to save");
return;
}
// prompt for a location to save it
if (this.dialog.ShowDialog() == true)
{
// the "using" block ensures the stream is cleaned up when we are finished
using (Stream stream = this.dialog.OpenFile())
{
// encode the stream
JPGUtil.EncodeJpg(bitmap, stream);
}
}
}
finally
{
// restart the capture timer
this.timer.Start();
}
}
Related
In my application I let the users select an image (of any size). The application will then load it to an image control, resize it if needed, and display it on the screen.
I have all the saving / loading from the preferences working correctly right now as I use the Xamarin Forms Plugin.FilePicker and grab the byte array from that to save to my preferences.
The challenge I am facing is that if the uses pics a large image from their device, the large version of the image is what is uploaded to the FilePicker plugin and the byte array is too large to save. (I get the error ' The size of the state manager setting value has exceeded the limit.')
So what I would like to do is take the contents of the image control, which have been resized to a manageable size, convert that to a byte array and then save that in my preferences.
Any idea how I can convert the content of the image control into a byte array so I can serialize it in JSON and save it to my preferences?? Below is that code that saves the Byte Array from the file picker.
private async void btnChooseFile_Clicked(object sender, System.EventArgs e)
{
try
{
FileData fileData = await CrossFilePicker.Current.PickFile();
if (fileData == null)
return; // user canceled file picking
//lblFilePath.Text = fileData.FileName;
imgIcon.Source = ImageSource.FromStream(() => fileData.GetStream());
// THIS IS THE LINE OF CODE I NEED TO CHANGE TO IT SAVES THE
// BYTE ARRAY OF THE SMALLER IMAGE AS DISPLAYED BY THE
// IMAGE CONTROL INSTEAD OF THE FULL SIZE FILE THE USER
// SELECTED
ViewModelObjects.AppSettings.KioskIcon = fileData.DataArray;
}
catch (Exception ex)
{
System.Console.WriteLine("Exception choosing file: " + ex.ToString());
}
}
you could resize the image size befor assigning the value to the image control:
#if __IOS__
public static byte[] ResizeImageIOS(byte[] imageData, float width, float height)
{
UIImage originalImage = ImageFromByteArray(imageData);
UIImageOrientation orientation = originalImage.Orientation;
//create a 24bit RGB image
using (CGBitmapContext context = new CGBitmapContext(IntPtr.Zero,
(int)width, (int)height, 8,
4 * (int)width, CGColorSpace.CreateDeviceRGB(),
CGImageAlphaInfo.PremultipliedFirst))
{
RectangleF imageRect = new RectangleF(0, 0, width, height);
// draw the image
context.DrawImage(imageRect, originalImage.CGImage);
UIKit.UIImage resizedImage = UIKit.UIImage.FromImage(context.ToImage(), 0, orientation);
// save the image as a jpeg
return resizedImage.AsJPEG().ToArray();
}
}
#if __ANDROID__
public static byte[] ResizeImageAndroid (byte[] imageData, float width, float height)
{
// Load the bitmap
Bitmap originalImage = BitmapFactory.DecodeByteArray (imageData, 0, imageData.Length);
Bitmap resizedImage = Bitmap.CreateScaledBitmap(originalImage, (int)width, (int)height, false);
using (MemoryStream ms = new MemoryStream())
{
resizedImage.Compress (Bitmap.CompressFormat.Jpeg, 100, ms);
return ms.ToArray ();
}
}
you could refer to ImageResizer
I'm working on a Tiff Viewer project which deals with big 24bit colored tif files (>70MB).
Here is the code how I load the tif file:
TiffBitmapDecoder tbd = new TiffBitmapDecoder(new Uri(_strTiffPath),BitmapCreateOptions.DelayCreation, BitmapCacheOption.Default);
_frames = tbd.Frames;
I use the default cache option to prevent loading the whole file in memory.
My application has a side thumbnails view (vertical StackPanel with Image), and a Page view which views the selected thumbnail.
I load only visible thumbnails by this code:
internal static BitmapSource GetThumbAt(int i)
{
try
{
if (i >= _frames.Count)
return null;
BitmapFrame bf = _frames[i];
bf.Freeze();
return bf;
}
catch (Exception ex)
{
return null;
}
}
My problem is when I scroll down the thumbnails view to load the new visible pages, the memory load increases and I run into out of memory !
I tried to unload invisible pages (that were already loaded) but that doesn't help !
img.Source = null
Thank you helping me to figure this out.
I figured it out !
As mentioned in my previous comment, this article helped me a lot.
I just adapted it to my code and the memory is now unloading correctly.
Here are the modifications I made to my code:
internal static BitmapSource GetThumbAt(int i)
{
try
{
if (i >= _frames.Count)
return null;
BitmapFrame bf = _frames[i];
BitmapSource bs = bf.Clone() as BitmapSource; //make a copy of the original because bf is frozen and can't take any new property
BitmapUtility.AddMemoryPressure(bs);
return bs;
}
catch (Exception ex)
{
return null;
}
}
I have a WebBrowser control on a form, but for the most part it remains hidden from the user. It is there to handle a series of login and other tasks. I have to use this control because there is a ton of Javascript that handles the login. (i.e., I can't just switch to a WebClient object.)
After hopping around a bit, we end up wanting to download a PDF file. But instead of downloading, the file is displayed within the webBrowser control, which the user can not see.
How can I download the PDF instead of having it load in the browser control?
Add a SaveFileDialog control to your form, then add the following code on your WebBrowser's Navigating event:
private void webBrowser1_Navigating(object sender, WebBrowserNavigatingEventArgs e)
{
if (e.Url.Segments[e.Url.Segments.Length - 1].EndsWith(".pdf"))
{
e.Cancel = true;
string filepath = null;
saveFileDialog1.FileName = e.Url.Segments[e.Url.Segments.Length - 1];
if (saveFileDialog1.ShowDialog() == DialogResult.OK)
{
filepath = saveFileDialog1.FileName;
WebClient client = new WebClient();
client.DownloadFileCompleted += new AsyncCompletedEventHandler(client_DownloadFileCompleted);
client.DownloadFileAsync(e.Url, filepath);
}
}
}
//Callback function
void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
MessageBox.Show("File downloaded");
}
Source: http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/d338a2c8-96df-4cb0-b8be-c5fbdd7c9202
The solution I ended up using:
I did everything else as-needed to get the URL where it needed to go. Knowing that all of the login information, required settings, viewstates, etc. were stored in the cookies, I was finally able to grab the file using a hybrid of the web control to navigate then the WebClient object to actually snag the file bytes.
public byte[] GetPDF(string keyValue)
{
DoLogin();
// Ask the source to generate the PDF. The PDF doesn't
// exist on the server until you have visited this page
// at least ONCE. The PDF exists for five minutes after
// the visit, so you have to snag it pretty quick.
LoadUrl(string.Format(
"https://www.theMagicSource.com/getimage.do?&key={0}&imageoutputformat=PDF",
keyValue));
// Now that we're logged in (not shown here), and
// (hopefully) at the right location, snag the cookies.
// We can use them to download the PDF directly.
string cookies = GetCookies();
byte[] fileBytes = null;
try
{
// We are fully logged in, and by now, the PDF should
// be generated. GO GET IT!
WebClient wc = new WebClient();
wc.Headers.Add("Cookie: " + cookies);
string tmpFile = Path.GetTempFileName();
wc.DownloadFile(string.Format(
"https://www.theMagicSource.com/document?id={0}_final.PDF",
keyValue), tmpFile);
fileBytes = File.ReadAllBytes(tmpFile);
File.Delete(tmpFile);
}
catch (Exception ex)
{
// If we can't get the PDF here, then just ignore the error and return null.
throw new WebScrapePDFException(
"Could not find the specified file.", ex);
}
return fileBytes;
}
private void LoadUrl(string url)
{
InternalBrowser.Navigate(url);
// Let the browser control do what it needs to do to start
// processing the page.
Thread.Sleep(100);
// If EITHER we can't continue OR
// the web browser has not been idle for 10 consecutive seconds yet,
// then wait some more.
// ...
// ... Some stuff here to make sure the page is fully loaded and ready.
// ... Removed to reduce complexity, but you get the idea.
// ...
}
private string GetCookies()
{
if (InternalBrowser.InvokeRequired)
{
return (string)InternalBrowser.Invoke(new Func<string>(() => GetCookies()));
}
else
{
return InternalBrowser.Document.Cookie;
}
}
bool documentCompleted = false;
string getInnerText(string url)
{
documentCompleted = false;
web.Navigate(url);
while (!documentCompleted)
Application.DoEvents();
return web.Document.Body.InnerText;
}
private void web_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
documentCompleted = true;
}
I have come across a couple of different ways to write images to isolated storage on some Windows Phone sites, however I am unsure which is the best to use for a camera app or if there are some that are better than others:
The first is from this post on a basic camera application: http://msdn.microsoft.com/en-us/library/hh202956(v=VS.92).aspx It takes the jpeg from the camera and writes it to isolated storage directly.
void cam_CaptureImageAvailable(object sender, Microsoft.Devices.ContentReadyEventArgs e)
{
string fileName = savedCounter + ".jpg";
try
{ // Write message to the UI thread.
Deployment.Current.Dispatcher.BeginInvoke(delegate()
{
txtDebug.Text = "Captured image available, saving picture.";
});
// Save picture to the library camera roll.
library.SavePictureToCameraRoll(fileName, e.ImageStream);
// Write message to the UI thread.
Deployment.Current.Dispatcher.BeginInvoke(delegate()
{
txtDebug.Text = "Picture has been saved to camera roll.";
});
// Set the position of the stream back to start
e.ImageStream.Seek(0, SeekOrigin.Begin);
// Save picture as JPEG to isolated storage.
using (IsolatedStorageFile isStore = IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream targetStream = isStore.OpenFile(fileName, FileMode.Create, FileAccess.Write))
{
// Initialize the buffer for 4KB disk pages.
byte[] readBuffer = new byte[4096];
int bytesRead = -1;
// Copy the image to isolated storage.
while ((bytesRead = e.ImageStream.Read(readBuffer, 0, readBuffer.Length)) > 0)
{
targetStream.Write(readBuffer, 0, bytesRead);
}
}
}
// Write message to the UI thread.
Deployment.Current.Dispatcher.BeginInvoke(delegate()
{
txtDebug.Text = "Picture has been saved to isolated storage.";
});
}
finally
{
// Close image stream
e.ImageStream.Close();
}
}
It seems to use a 4kb Buffer, is there any point in doing it this way? Seems a bit more complicated than this method which converts the image to a bitmap then uses the save as Jpeg method (http://www.windowsphonegeek.com/tips/All-about-WP7-Isolated-Storage---Read-and-Save-Images):
// Create a filename for JPEG file in isolated storage.
String tempJPEG = "logo.jpg";
// Create virtual store and file stream. Check for duplicate tempJPEG files.
using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
if (myIsolatedStorage.FileExists(tempJPEG))
{
myIsolatedStorage.DeleteFile(tempJPEG);
}
IsolatedStorageFileStream fileStream = myIsolatedStorage.CreateFile(tempJPEG);
StreamResourceInfo sri = null;
Uri uri = new Uri(tempJPEG, UriKind.Relative);
sri = Application.GetResourceStream(uri);
BitmapImage bitmap = new BitmapImage();
bitmap.SetSource(sri.Stream);
WriteableBitmap wb = new WriteableBitmap(bitmap);
// Encode WriteableBitmap object to a JPEG stream.
Extensions.SaveJpeg(wb, fileStream, wb.PixelWidth, wb.PixelHeight, 0, 85);
//wb.SaveJpeg(fileStream, wb.PixelWidth, wb.PixelHeight, 0, 85);
fileStream.Close();
}
If there are any alternative methods you have also I'd be interested, thanks!
Think you should check this out:
I believe I already answered this and got a +50 bounty SO Save image to Isolated Storaged using byte[]
BACKGROUND
I have a media file that I am progressively downloading to my Silverlight 4 application, using WebClient.OpenReadAsync/OpenReadCompleted, and Stream.BeginRead/AsyncCallback. The goal is to play the file in a MediaElement by calling the SetSource method, passing in an instance of our custom MediaStreamSource, so that the file can start playing before the entire contents of the file have been downloaded. The media file is using custom encoding/decoding, which is why we are using a custom MediaStreamSource. Our MediaStreamSource is built to accept a Stream and begin parsing track information and play back in a MediaElement. I have confirmed I am progressively downloading the file contents. Here is a summary of the download code:
public void SetSource(string sourceUrl)
{
var uriBuilder = new UriBuilder(sourceUrl);
WebClient webClient = new WebClient();
// AllowReadStreamBuffering = false allows us to get the stream
// before it's finished writing to it.
webClient.AllowReadStreamBuffering = false;
webClient.OpenReadCompleted += new OpenReadCompletedEventHandler(webClient_OpenReadCompleted);
webClient.OpenReadAsync(uriBuilder.Uri);
}
void webClient_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
_inboundVideoStream = e.Result;
BeginReadingFromStream();
}
private void BeginReadingFromStream()
{
if (_inboundVideoStream.CanRead)
{
_chunk = new byte[_chunkSize];
_inboundVideoStream.BeginRead(_chunk, 0, _chunk.Length, new AsyncCallback(BeginReadCallback), _inboundVideoStream);
}
}
private void BeginReadCallback(IAsyncResult asyncResult)
{
Stream stream = asyncResult.AsyncState as Stream;
int bytesRead = stream.EndRead(asyncResult);
_totalBytesRead += bytesRead;
if (_playableStream == null)
_playableStream = new MemoryStream();
_playableStream.Write(_chunk, 0, _chunk.Length);
if (!_initializedMediaStream && _playableStream.Length >= _minimumToStartPlayback)
{
_initializedMediaStream = true;
// Problem: we can't hand the stream source a stream that's still being written to
// It's Position is at the end. Can I read and write from the same stream or is there another way
MP4MediaStreamSource streamSource = new MP4MediaStreamSource(_playableStream);
this.Dispatcher.BeginInvoke(() =>
{
mediaElement1.SetSource(streamSource);
});
}
if (_totalBytesRead < _fileSize)
{
ReadFromDownloadStream();
}
else
{
// Finished downloading
}
}
I've tried both writing/reading to a MemoryStream simultaneously, as listed above, as well as writing to an IsolatedStorageFile and reading from that file as I'm writing to it. So far I can't find a way to make either approach work.
QUESTION:
Is there a way to read and write to the same stream? Or is there a standard way to implement this with a stream and MediaStreamSource?
Thanks
The way I did it in my MediaStreamSource implementation is to have 2 streams in it: one for reading and one for writing.
I dispose and re-create the reading stream using the buffer of the writing stream every time GetSampleAsync() is called. Another way to do it I guess is to use a negative offset when creating a MediaStreamSample to pass to ReportGetSampleCompleted() since the position of the stream will always be at the end, but you have to make sure that the position is at the end otherwise this will not work, to keep it simple I just used 2 streams