I encounter a problem when inserting an image in PPTX document.
I want to create a new slide based on slide mask. I used this code to set picture in existing a shape
class Program
{
public static void Run()
{
string dataDir = ConfigurationManager.AppSettings["directoryToSave"];
string srcDir = String.Concat(ConfigurationManager.AppSettings["Source"], "Master.pptx");
string appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
//string file = Path.Combine(appData, srcDir);
using (Presentation presentation = new Presentation(srcDir))
{
IMasterLayoutSlideCollection layoutSlides = presentation.Masters[0].LayoutSlides;
ILayoutSlide layoutSlide = null;
foreach (ILayoutSlide titleAndObjectLayoutSlide in layoutSlides)
{
if (titleAndObjectLayoutSlide.Name == "TITRE_CONTENU")
{
layoutSlide = titleAndObjectLayoutSlide;
break;
}
}
string filePath = String.Concat(ConfigurationManager.AppSettings["Source"], #"Logos\bp.png");
Image imgs = (Image)new Bitmap(filePath);
setShapePicture(presentation, layoutSlide, "picture", imgs);
presentation.Slides.InsertEmptySlide(0, layoutSlide);
presentation.Save(dataDir + "AddLayoutSlides_out.pptx", SaveFormat.Pptx);
}
}
public static void setShapePicture(Presentation doc, ILayoutSlide layoutSlide, string shapeName, Image image)
{
var logo_shape = layoutSlide.Shapes.SingleOrDefault(r => r.Name.Equals(shapeName));
IPPImage imgx = doc.Images.AddImage(image);
//Add Picture Frame with height and width equivalent of Picture
logo_shape.FillFormat.FillType = FillType.Picture;
// Set the picture fill mode
logo_shape.FillFormat.PictureFillFormat.PictureFillMode = PictureFillMode.Stretch;
// Set the picture
logo_shape.FillFormat.PictureFillFormat.Picture.Image = imgx;
}
static void Main(string[] args)
{
try
{
var path = ConfigurationManager.AppSettings["sourceAsposeLicensePath"];
License license = new License();
license.SetLicense(path);
Run();
}
catch (Exception ex)
{
Console.WriteLine("Error" + ex.Message);
}
finally
{
Console.WriteLine("Terminated");
Console.ReadKey();
}
}
}
What I get in the generated file is a shape with background picture and a placeholder. You can find all resources in this link MasterSlide+Logos+Output
I have observed the requirements shared by you and like to share that placeholder is not an actual shape but gives a skeleton for shape. I have created a sample code for your convenience that may help you in achieving your requirements.
public static void TestPlaceholderImage()
{
String path = "C:\\Aspose Data\\";
Presentation pres = new Presentation(path + "TestPicture.pptx");
foreach (ISlide slide in pres.Slides)
{
foreach (IShape shape in slide.Shapes)
{
if (shape.Placeholder != null)
{
if (shape.Placeholder.Type == PlaceholderType.Picture)
{
// Instantiate the ImageEx class
System.Drawing.Image img = (System.Drawing.Image)new Bitmap(#"C:\Users\Public\Pictures\Sample Pictures\Desert.jpg");
IPPImage imgx = pres.Images.AddImage(img);
shape.FillFormat.FillType = FillType.Picture;
shape.FillFormat.PictureFillFormat.Picture.Image = imgx;
if (shape is AutoShape)
{
ITextFrame text = ((IAutoShape)shape).TextFrame;
text.Text = " ";
text.Paragraphs[0].ParagraphFormat.Bullet.Type = BulletType.None;
}
}
}
}
}
pres.Save(path + "Addedpic.pptx", Aspose.Slides.Export.SaveFormat.Pptx);
}
I am working as Support developer/ Evangelist at Aspose.
SampleData.zip
Related
I am building a screen recording app in C# using Windows Graphics Capture API. I am using this script. I can select monitor and can record it to mp4 file. I can also select a Window and record it too. But how can we record a region with this? Ideally I need to give x,y coordinates along with width and height to record that specific region.
Here are the functions which return GraphicsCaptureItem for Window or Monitor hwnd, which can be used to record.
public static GraphicsCaptureItem CreateItemForWindow(IntPtr hwnd)
{
var factory = WindowsRuntimeMarshal.GetActivationFactory(typeof(GraphicsCaptureItem));
var interop = (IGraphicsCaptureItemInterop)factory;
var temp = typeof(GraphicsCaptureItem);
var itemPointer = interop.CreateForWindow(hwnd, GraphicsCaptureItemGuid);
var item = Marshal.GetObjectForIUnknown(itemPointer) as GraphicsCaptureItem;
Marshal.Release(itemPointer);
return item;
}
public static GraphicsCaptureItem CreateItemForMonitor(IntPtr hmon)
{
var factory = WindowsRuntimeMarshal.GetActivationFactory(typeof(GraphicsCaptureItem));
var interop = (IGraphicsCaptureItemInterop)factory;
var temp = typeof(GraphicsCaptureItem);
var itemPointer = interop.CreateForMonitor(hmon, GraphicsCaptureItemGuid);
var item = Marshal.GetObjectForIUnknown(itemPointer) as GraphicsCaptureItem;
Marshal.Release(itemPointer);
return item;
}
And this is Recording function
private async void RecordScreen(GraphicsCaptureItem item)
{
_device = Direct3D11Helpers.CreateDevice();
// Get our encoder properties
uint frameRate = 30;
uint bitrate = 3 * 1000000;
var width = (uint)item.Size.Width;
var height = (uint)item.Size.Height;
// Kick off the encoding
try
{
newFile = GetTempFile();
using (var stream = new FileStream(newFile, FileMode.CreateNew).AsRandomAccessStream())
using (_encoder = new Encoder(_device, item))
{
await _encoder.EncodeAsync(
stream,
width, height, bitrate,
frameRate);
}
}
catch (Exception ex)
{}
}
I achieved this by passing a custom region to CopySubresourceRegion in WaitForNewFrame method.
public SurfaceWithInfo WaitForNewFrame()
{
.....
using (var multithreadLock = new MultithreadLock(_multithread))
using (var sourceTexture = Direct3D11Helpers.CreateSharpDXTexture2D(_currentFrame.Surface))
{
.....
using (var copyTexture = new SharpDX.Direct3D11.Texture2D(_d3dDevice, description))
{
.....
var region = new SharpDX.Direct3D11.ResourceRegion(
_region.Left,
_region.Top,
0,
_region.Left + _region.Width,
_region.Top + _region.Height,
1
);
_d3dDevice.ImmediateContext.CopyResource(_blankTexture, copyTexture);
_d3dDevice.ImmediateContext.CopySubresourceRegion(sourceTexture, 0, region, copyTexture, 0);
result.Surface = Direct3D11Helpers.CreateDirect3DSurfaceFromSharpDXTexture(copyTexture);
}
}
....
}
I have an method which is download images via URL and sometimes URL become like this, which contains very long path (i removed some string,it just didnt beacome long question :) : data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBxITEhUSEBAVFhMXGRcXFRgWFRcVGRcYFhcXFhUVGBgYISggGBslGxgaITEhJSkrLi8uGCAzODMsNygtLisBCgoKDg0OFxAQGysfHSUtLS8tLS0tLS0tLSstLS0wLS4tLS0tLS0tLS0tKystNy0uLy0rKy0tLS0rNS0tLS0tLf/AABEIALoBDwMBIgACEQEDEQH/xAAcAAEAAgIDAQAAAAAAAAAAAAAABAUCBgEDBwj/xABLEAABAwMCAgYDCgsHAwUAAAABAAIDBBESBSExQQYTFCJRYXGBkQcjMkJTVJOh0fAVJDNSYpKUscHS4RYXQ1VjcoKEorJEg6TCw//EABkBAQEBAQEBAAAAAAAAAAAAAAABAgMEBf/EACURAQEAAgIABQQDAAAAAAAAAAABAhEDIQQSMWFxQYGh0QUTUf/aAAwDAQACEQMRAD8A9xREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQERaH0h90yGnnfAyB8hYcXnIMGQ4gbG/p2Qb4i8p1v3S5JYsKZjoJLtOd2v2B7zcS224Vezp9WBtjISfGzRf1Yq6Tb2ZF4vN7o1WxhJJNud2j6sFd9HPdJc98UUrLukIsTxsSG/FAHHyTRt6aiIooiIgIiICIiAiIgIiICIiAiIgIiICLQPdM6eu09zIomgyOAeSd7NJc22J8S3jflwWtRe6lOWA2Nz+ixWQ29kReR/wB5suNrSZ+OMdvYrLT/AHVImsAnhmc/mWiMA/8AcP3Jqm3pSLU+jPT6mrJepY2SN5BLRIG96wuQC0ncAX3W2KAiIgIiIC+Zdbqc6uodfjNKfV1hsvpeeQNaXHgASfULr5WgeS5zjxO59JN1YlV2txh1S+9+DedvihRuzDll+sV36i78Yf8A8f8AxauHnYrUgvNa6MGmfKXOqXxRmMZX6okv3dfLLhwsAd3i9sSDC0mgZO4hjp2hjDI976lrGNawxhzr9X+c4gDxezwJPoPS8Na2okfA17Gy0Tne9NbsDGHMBLiRk1rmk+TmnjYU/Seth1LrYaGJ8kgpy8PdHHE4lk0TnRNYxoLhgBxN+4OO6zbpdKJjbgW1GUE346jHsQDx8r2+tZNikc5rY9Qnc5xxaG1zXnibEhlzb4PAcneVuqHR6kNv2V4cRnbstmhx7mHwdm4d7h8McPjKVQ6HKZYwYJQ0PYS50JjIZEQWuyHxyC644ktbudrZVArqqWJ5Y6rrDaxDm1Jc1zXAOa5p2uC0+A34gWIXXBqErnNa2qri5xa0ATm7nOLQAN+JJcB/x81ues6tRR0r6eeEds6ppwELXWlkizDnTD4OJcBYEEY8CFpPRvTTUztiLywWfI5zW5ODYmOkd1bR8J/dsB4lal63UqZqT6mnf1dRUV8cmIdi6e5s6+JNn7bj2KFJq7x/6yu5/wCMf0rX7/8As/7vJTtboGOpoq6CeeSJ73QWqQOtY6MF1g4Eh7LHa3C9uRVl0a1bTYqGojrIgZiXFvvHWueMW9W1ribMs4OJ4cRv4tzXSR3w9G68sa91ZVR5Nza2SoIfgT3SWh5xuOF7IejFf/mMvK/4y/8ARvxeP0/Y3xNrbpTptdN1U0MdTIHRtPvdzjtvcRkcrAHyB5Kh/A+pgginrfU2Yf8A22F7gLkdTe3GXA6pYdW1+boW2uSQY+HEWHO/eGwFyOuXVIopDBT0TJWxho6yXKR0pc3IOFm37wu4AkbA7AbLlusnb8Tp7DicHgG++RIbwDO/tbu778F6cPBc3JjMscer8JeTGdWq3WqWoe4NfWCYC+5aWAOyc3bEHIWFAiIgIiICIiD/2Q==
And then when i debug or when its come to download image, i get this Exception:
var DL = webClient.DownloadData(base64)
The specified path and / or file name is too long. The fully qualified
name must be less than 260 characters and the folder name must be less
than 248 characters.
i did also research which is suggested to add <httpRuntime maxUrlLength="260" /> in webconfig or used different library , but unfortunately it didnt help to solve the problem.
Can anyone please help me or point me into the right direction :)
Thanks in advance.
Controller:
[HttpPost]
public string DownloadImagesFromLinkViaURL(ImagesViewModel model)
{
var RandomName = Guid.NewGuid().ToString("N").Substring(0,12);
using (WebClient webClient = new WebClient())
{
try
{
string base64 = model.ImageURL.Substring(model.ImageURL.IndexOf(',') + 1);
byte[] data = Convert.FromBase64String(base64);
var DL = webClient.DownloadData(base64);
using (MemoryStream mem = new MemoryStream(DL))
{
using (var content = Image.FromStream(mem))
{
var format = ImageFormat.Png.ToString().ToLower();
var PathIMG = "https://SomeName.com/folder/" + RandomName + "." + format;
content.Save(Path.Combine(Server.MapPath(PathIMG)));
ImageStore img = new ImageStore();
img.ProducentVarenr = model.ImageName;
img.ImageOrginalURL = model.ImageURL;
img.ImageRandomName = RandomName;
img.LinktilBillede = PathIMG;
db.ImageStoreList.Add(img);
db.SaveChanges();
}
}
}
catch (ArgumentException)
{
return "content is not image";
}
}
return "saved";
}
ViewModal:
public class ImagesViewModel
{
public int ImageID { get; set; }
public string ImageURL { get; set; }
public string ImageName { get; set; }
public string ImagePath { get; set; }
public string RandomName { get; set; }
}
Data you see is not url or path. It is image data presented as Base64 string. So no any downloading is needed since you have image data already.
If you paste that very long string i.e this base64-to-image converter tool, you see actual image.
With given base64-string you can save it to file with following style:
File.WriteAllBytes(#"c:\yourfile", Convert.FromBase64String(base64));
Here is (non-tested and non-refactored) fixed version of your original method, as requested in answer comments.
[HttpPost]
public string DownloadImagesFromLinkViaURL(ImagesViewModel model)
{
var RandomName = Guid.NewGuid().ToString("N").Substring(0, 12);
var format = ImageFormat.Png.ToString().ToLower();
var PathIMG = "https://SomeName.com/folder/" + RandomName + "." + format;
if (model.ImageURL.StartsWith("data:image"))
{
string base64 = model.ImageURL.Substring(model.ImageURL.IndexOf(',') + 1);
File.WriteAllBytes($#"c:\temp\{RandomName}.jpeg", Convert.FromBase64String(base64));
ImageStore img = new ImageStore();
img.ProducentVarenr = model.ImageName;
img.ImageOrginalURL = model.ImageURL;
img.ImageRandomName = RandomName;
img.LinktilBillede = PathIMG;
db.ImageStoreList.Add(img);
db.SaveChanges();
return "saved";
}
using (WebClient webClient = new WebClient())
{
try
{
byte[] data = Convert.FromBase64String(base64);
var DL = webClient.DownloadData(base64);
using (MemoryStream mem = new MemoryStream(DL))
{
using (var content = Image.FromStream(mem))
{
content.Save(Path.Combine(Server.MapPath(PathIMG)));
ImageStore img = new ImageStore();
img.ProducentVarenr = model.ImageName;
img.ImageOrginalURL = model.ImageURL;
img.ImageRandomName = RandomName;
img.LinktilBillede = PathIMG;
db.ImageStoreList.Add(img);
db.SaveChanges();
}
}
}
catch (ArgumentException)
{
return "content is not image";
}
}
return "saved";
}
I am using ELCImagepicker.dll to create gallery with multi image selection. Everything is working fine.
1- I want to change icon of Tick whenever user select. It's very old style
2- Change validation message of maximum selection. I want to use the word "select" instead of "send".
Here is the MediaService file. maxImage set validation of maximum images
public class MediaService : IMediaService
{
public async Task OpenGallery(int maxImage)
{
var picker = ELCImagePickerViewController.Create(maxImage);
picker.MaximumImagesCount = maxImage;
var topController = UIApplication.SharedApplication.KeyWindow.RootViewController;
while (topController.PresentedViewController != null)
{
topController = topController.PresentedViewController;
}
topController.PresentViewController(picker, true, null);
List<string> images = new List<string>();
await picker.Completion.ContinueWith(t =>
{
picker.BeginInvokeOnMainThread(() =>
{
//dismiss the picker
picker.DismissViewController(true, null);
if (t.IsCanceled || t.Exception != null)
{
}
else
{
//List<string> images = new List<string>();
var items = t.Result as List<AssetResult>;
foreach (var item in items)
{
var path = Save(item.Image, item.Name);
images.Add(path);
//CleanPath(path);
}
}
});
});
MessagingCenter.Send<App, List<string>>((App)Xamarin.Forms.Application.Current, "ImagesSelected", images);
}
string Save(UIImage image, string name)
{
var documentsDirectory = Environment.GetFolderPath
(Environment.SpecialFolder.Personal);
string jpgFilename = System.IO.Path.Combine(documentsDirectory, name); // hardcoded filename, overwritten each time
NSData imgData = image.AsJPEG();
NSError err = null;
if (imgData.Save(jpgFilename, false, out err))
{
return jpgFilename;
}
else
{
Console.WriteLine("NOT saved as " + jpgFilename + " because" + err.LocalizedDescription);
return null;
}
}
void IMediaService.ClearFiles(List<string> filePaths)
{
var documentsDirectory = Environment.GetFolderPath
(Environment.SpecialFolder.Personal);
if (Directory.Exists(documentsDirectory))
{
foreach (var p in filePaths)
{
File.Delete(p);
}
}
}
}
Please guide
Since the author hasn't expose the api that can change icon or text,so you have to change them inside the source code, and then create dll for using.
Alert text :here
Icon : here
I'm trying to find a working sample to record videos with IOS (using xamarin) but there's always something missing or not working for me.
My best try using several forum posts and samples is the following :
using System;
using CoreGraphics;
using Foundation;
using UIKit;
using AVFoundation;
using CoreVideo;
using CoreMedia;
using CoreFoundation;
using System.IO;
using AssetsLibrary;
namespace avcaptureframes {
public partial class AppDelegate : UIApplicationDelegate {
public static UIImageView ImageView;
UIViewController vc;
AVCaptureSession session;
OutputRecorder outputRecorder;
DispatchQueue queue;
public override bool FinishedLaunching (UIApplication application, NSDictionary launchOptions)
{
ImageView = new UIImageView (new CGRect (10f, 10f, 200f, 200f));
ImageView.ContentMode = UIViewContentMode.Top;
vc = new UIViewController {
View = ImageView
};
window.RootViewController = vc;
window.MakeKeyAndVisible ();
window.BackgroundColor = UIColor.Black;
if (!SetupCaptureSession ())
window.AddSubview (new UILabel (new CGRect (20f, 20f, 200f, 60f)) {
Text = "No input device"
});
return true;
}
bool SetupCaptureSession ()
{
// configure the capture session for low resolution, change this if your code
// can cope with more data or volume
session = new AVCaptureSession {
SessionPreset = AVCaptureSession.PresetMedium
};
// create a device input and attach it to the session
var captureDevice = AVCaptureDevice.DefaultDeviceWithMediaType (AVMediaType.Video);
if (captureDevice == null) {
Console.WriteLine ("No captureDevice - this won't work on the simulator, try a physical device");
return false;
}
//Configure for 15 FPS. Note use of LockForConigfuration()/UnlockForConfiguration()
NSError error = null;
captureDevice.LockForConfiguration (out error);
if (error != null) {
Console.WriteLine (error);
captureDevice.UnlockForConfiguration ();
return false;
}
if (UIDevice.CurrentDevice.CheckSystemVersion (7, 0))
captureDevice.ActiveVideoMinFrameDuration = new CMTime (1, 15);
captureDevice.UnlockForConfiguration ();
var input = AVCaptureDeviceInput.FromDevice (captureDevice);
if (input == null) {
Console.WriteLine ("No input - this won't work on the simulator, try a physical device");
return false;
}
session.AddInput (input);
// create a VideoDataOutput and add it to the sesion
var settings = new CVPixelBufferAttributes {
PixelFormatType = CVPixelFormatType.CV32BGRA
};
using (var output = new AVCaptureVideoDataOutput { WeakVideoSettings = settings.Dictionary }) {
queue = new DispatchQueue ("myQueue");
outputRecorder = new OutputRecorder ();
output.SetSampleBufferDelegate (outputRecorder, queue);
session.AddOutput (output);
}
session.StartRunning ();
return true;
}
public override void OnActivated (UIApplication application)
{
}
public class OutputRecorder : AVCaptureVideoDataOutputSampleBufferDelegate
{
AVAssetWriter writer=null;
AVAssetWriterInput writerinput= null;
CMTime lastSampleTime;
int frame=0;
NSUrl url;
public OutputRecorder()
{
string tempFile = Path.Combine(Path.GetTempPath(), "NewVideo.mp4");
if (File.Exists(tempFile)) File.Delete(tempFile);
url = NSUrl.FromFilename(tempFile);
NSError assetWriterError;
writer = new AVAssetWriter(url, AVFileType.Mpeg4, out assetWriterError);
var outputSettings = new AVVideoSettingsCompressed()
{
Height = 300,
Width = 300,
Codec = AVVideoCodec.H264,
CodecSettings = new AVVideoCodecSettings
{
AverageBitRate = 1000000
}
};
writerinput = new AVAssetWriterInput(mediaType: AVMediaType.Video, outputSettings: outputSettings);
writerinput.ExpectsMediaDataInRealTime = false;
writer.AddInput(writerinput);
}
public override void DidOutputSampleBuffer (AVCaptureOutput captureOutput, CMSampleBuffer sampleBuffer, AVCaptureConnection connection)
{
try
{
lastSampleTime = sampleBuffer.PresentationTimeStamp;
var image = ImageFromSampleBuffer(sampleBuffer);
if (frame == 0)
{
writer.StartWriting();
writer.StartSessionAtSourceTime(lastSampleTime);
frame = 1;
}
String infoString = "";
if (writerinput.ReadyForMoreMediaData)
{
if (!writerinput.AppendSampleBuffer(sampleBuffer))
{
infoString = "Failed to append sample buffer";
}
else
{
infoString = String.Format("{0} frames captured", frame++);
}
}
else
{
infoString = "Writer not ready";
}
Console.WriteLine(infoString);
ImageView.BeginInvokeOnMainThread(() => ImageView.Image = image);
}
catch (Exception e)
{
Console.WriteLine(e);
}
finally
{
sampleBuffer.Dispose();
}
}
UIImage ImageFromSampleBuffer (CMSampleBuffer sampleBuffer)
{
// Get the CoreVideo image
using (var pixelBuffer = sampleBuffer.GetImageBuffer () as CVPixelBuffer)
{
// Lock the base address
pixelBuffer.Lock (CVOptionFlags.None);
// Get the number of bytes per row for the pixel buffer
var baseAddress = pixelBuffer.BaseAddress;
var bytesPerRow = (int)pixelBuffer.BytesPerRow;
var width = (int)pixelBuffer.Width;
var height = (int)pixelBuffer.Height;
var flags = CGBitmapFlags.PremultipliedFirst | CGBitmapFlags.ByteOrder32Little;
// Create a CGImage on the RGB colorspace from the configured parameter above
using (var cs = CGColorSpace.CreateDeviceRGB ())
{
using (var context = new CGBitmapContext (baseAddress, width, height, 8, bytesPerRow, cs, (CGImageAlphaInfo)flags))
{
using (CGImage cgImage = context.ToImage ())
{
pixelBuffer.Unlock (CVOptionFlags.None);
return UIImage.FromImage (cgImage);
}
}
}
}
}
void TryDispose (IDisposable obj)
{
if (obj != null)
obj.Dispose ();
}
}
}
}
This works displaying live camera image and I get "frames captured" message in consol but I don't find how to record to file.
I read somewhere about adding VideoCapture but I don't know how to link with my code.
Any help will is welcome.
From your code, in the construct of class OutputRecorder you have defined the url where you want to save the recording:
string tempFile = Path.Combine(Path.GetTempPath(), "NewVideo.mp4");
if (File.Exists(tempFile)) File.Delete(tempFile);
url = NSUrl.FromFilename(tempFile);
It means you want to save the video in the tmp folder in the app's sandbox. If you want to use the video sometime later, I recommend you to change the folder to documents by using:
string filePath = Path.Combine(NSSearchPath.GetDirectories(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomain.User)[0], "NewVideo.mp4");
I notice that you have called session.StartRunning(); in the method bool SetupCaptureSession() to start recording. please add session.StopRunning(); to end recording then the video will be saved in the path we just defined above.
Moreover, you can retrieve the video with the path like:
NSData videoData = NSData.FromFile(filePath);
How can I take a screenshot with Xamarin.iOS and stored this image in UIImage.
I have seen several examples of Obj-C, but no C #
Even more elegant:
UIScreen.MainScreen.Capture ();
from Craig Dunn's site:
public void ScreenCapture()
{
var documentsDirectory = Environment.GetFolderPath
(Environment.SpecialFolder.Personal);
Console.WriteLine("start capture of frame: " + this.View.Frame.Size);
UIGraphics.BeginImageContext(View.Frame.Size);
var ctx = UIGraphics.GetCurrentContext();
if (ctx != null)
{
View.Layer.RenderInContext(ctx);
UIImage img = UIGraphics.GetImageFromCurrentImageContext();
UIGraphics.EndImageContext();
// Set to display in a UIImage control _on_ the view
imageLogo.Image = img;
// Save to Photos
img.SaveToPhotosAlbum(
(sender, args)=>{Console.WriteLine("image saved to Photos");}
);
// Save to application's Documents folder
string png = Path.Combine (documentsDirectory, "Screenshot.png");
// HACK: overwrite the splash screen. iSOFlair is the application name
//string png = Path.Combine (documentsDirectory, "../iSOFlair.app/Default.png");
NSData imgData = img.AsPNG();
NSError err = null;
if (imgData.Save(png, false, out err))
{
Console.WriteLine("saved as " + png);
} else {
Console.WriteLine("NOT saved as" + png +
" because" + err.LocalizedDescription);
}
}
else
{
Console.WriteLine("ctx null - doesn't seem to happen");
}
}
More elegant:
public static class UIViewExtensions {
public static UIImage AsImage(this UIView view) {
UIGraphics.BeginImageContextWithOptions(view.Bounds.Size, view.Opaque, 0);
view.Layer.RenderInContext(UIGraphics.GetCurrentContext());
UIImage img = UIGraphics.GetImageFromCurrentImageContext();
UIGraphics.EndImageContext();
return img;
}
public static UIImage TakeScreenshot() {
return UIApplication.SharedApplication.KeyWindow.AsImage();
}
}
Call UIViewExtensions.TakeScreenshot() to take a screenshot of the whole screen or you can call AsImage() to any view to get an UIImage representation of the view. It would be better to put the TakeScreenshot() method somewhere else as it is not an extension of the UIView class.
This code will take a screenshot and save the photo into the camera roll.
UIGraphics.BeginImageContext(UIScreen.MainScreen.Bounds.Size);
try
{
var mainLayer = UIApplication.SharedApplication.KeyWindow.Subviews[0].Layer;
mainLayer.RenderInContext(UIGraphics.GetCurrentContext());
var img = UIGraphics.GetImageFromCurrentImageContext();
img.SaveToPhotosAlbum((iRef, status) =>
{
if (status != null)
{
new UIAlertView("Problem", status.ToString(), null, "OK", null).Show();
}
else
{
new UIAlertView("Saved", "Saved", null, "OK", null).Show();
}
});
}
finally
{
UIGraphics.EndImageContext();
}
But to make sure your app didn't crash is to ask the user for the permission to save the images to the camera roll.
Add this into info.plist
<key>NSPhotoLibraryAddUsageDescription</key>
<string>This app requires read and write permission from the user.</string>
if you're adding it from the generic editor then "Privacy - Photo Library Additions Usage Description" will be the given option you will find out instead of "NSPhotoLibraryAddUsageDescription".