public Task <IBitmap> Load(Stream sourceStream, float?desiredWidth, float?desiredHeight) { var data = NSData.FromStream(sourceStream); var tcs = new TaskCompletionSource <IBitmap>(); UIApplication.SharedApplication.InvokeOnMainThread(() => { try { #if UIKIT var bitmap = UIImage.LoadFromData(data); if (bitmap == null) { throw new Exception("Failed to load image"); } tcs.TrySetResult(new CocoaBitmap(bitmap)); #else tcs.TrySetResult(new CocoaBitmap(new UIImage(data))); #endif } catch (Exception ex) { tcs.TrySetException(ex); } }); return(tcs.Task); }
public static PImage ToImage(this NSData data, CGSize destSize, nfloat destScale, Configuration config, TaskParameter parameters, BaseDecoder.RCTResizeMode resizeMode = BaseDecoder.RCTResizeMode.ScaleAspectFit, ImageInformation imageinformation = null, bool allowUpscale = false) { var decoded = BaseDecoder.SourceRegfToDecodedImage(data, destSize, destScale, config, parameters, resizeMode, imageinformation, allowUpscale); PImage result; if (decoded.IsAnimated) { #if __IOS__ result = PImage.CreateAnimatedImage(decoded.AnimatedImages .Select(v => v.Image) .Where(v => v?.CGImage != null).ToArray(), decoded.AnimatedImages.Sum(v => v.Delay) / 100.0); #elif __MACOS__ result = new PImage(); var repr = decoded.AnimatedImages .Select(v => v.Image.Representations().First()) .ToArray(); result.AddRepresentations(repr); #endif } else { result = decoded.Image; } return(result); }
public void CIKernel_BasicTest() { if (!TestRuntime.CheckSystemAndSDKVersion(8, 0)) { Assert.Inconclusive("Custom filters require iOS8+"); } Exception ex = null; var t = new Thread(() => { // This code will crash if an MKMapView has been created previously on // the same thread, so just run it on a different thread (MKMapViews can // only be created on the main thread). This is obviously an Apple bug, // and a radar has been filed: 19249153. ObjC test case: https://github.com/rolfbjarne/CIKernelMKMapViewCrash try { PlatformImage uiImg = new PlatformImage(NSBundle.MainBundle.PathForResource("Xam", "png", "CoreImage")); #if MONOMAC CIImage ciImg = new CIImage(uiImg.CGImage); CIContext context = new CIContext(null); #else CIImage ciImg = new CIImage(uiImg); CIContext context = CIContext.FromOptions(null); #endif foreach (CustomerFilterType type in Enum.GetValues(typeof(CustomerFilterType))) { MyCustomFilter filter = new MyCustomFilter(type); filter.MyImage = ciImg; CIImage outputImage = filter.OutputImage; CGImage cgImage = context.CreateCGImage(outputImage, outputImage.Extent); #if MONOMAC NSImage finalImg = new NSImage(cgImage, new CGSize()); #else UIImage finalImg = new UIImage(cgImage); #endif Assert.IsNotNull(finalImg, "CIKernel_BasicTest should not be null"); Assert.IsTrue(filter.CallbackHit, "CIKernel_BasicTest callback must be hit"); if (filter.IsColorKernel) { Assert.IsTrue(filter.kernel is CIColorKernel, "CIKernel_BasicTest we disagree that it is a color kernel"); } else { Assert.IsTrue(filter.kernel is CIWarpKernel, "CIKernel_BasicTest we disagree that it is a warp kernel"); } } } catch (Exception ex2) { ex = ex2; } }); t.Start(); t.Join(); if (ex != null) { throw ex; } }
protected override Task SetTargetAsync(PImage image, bool animated) { return(MainThreadDispatcher.PostAsync(() => { ThrowIfCancellationRequested(); PlatformTarget.Set(this, image, animated); })); }
public static IBitmap FromNative(this UIImage This, bool copy = false) { if (copy) { return(new CocoaBitmap((UIImage)This.Copy())); } return(new CocoaBitmap(This)); }
public static System.IO.Stream AsPngStream(this PImage image) { #if __IOS__ || __TVOS__ return(image.AsPNG()?.AsStream()); #elif __MACOS__ var imageRep = new NSBitmapImageRep(image.AsTiff()); return(imageRep.RepresentationUsingTypeProperties(NSBitmapImageFileType.Png) .AsStream()); #endif }
public static System.IO.Stream AsJpegStream(this PImage image, int quality = 80) { #if __IOS__ || __TVOS__ return(image.AsJPEG(quality / 100f).AsStream()); #elif __MACOS__ // todo: jpeg quality? var imageRep = new NSBitmapImageRep(image.AsTiff()); return(imageRep.RepresentationUsingTypeProperties(NSBitmapImageFileType.Jpeg) .AsStream()); #endif }
protected override async Task SetTargetAsync(PImage image, bool animated) { if (Target == null) { return; } await MainThreadDispatcher.PostAsync(() => { ThrowIfCancellationRequested(); PlatformTarget.Set(this, image, animated); }).ConfigureAwait(false); }
protected override Task <PImage> GenerateImageFromDecoderContainerAsync(IDecodedImage <PImage> decoded, ImageInformation imageInformation, bool isPlaceholder) { PImage result; if (decoded.IsAnimated) { #if __IOS__ result = PImage.CreateAnimatedImage(decoded.AnimatedImages .Select(v => v.Image) .Where(v => v?.CGImage != null).ToArray(), decoded.AnimatedImages.Sum(v => v.Delay) / 100.0); #elif __MACOS__ using (var mutableData = NSMutableData.Create()) { var fileOptions = new CGImageDestinationOptions { GifDictionary = new NSMutableDictionary() }; fileOptions.GifDictionary[ImageIO.CGImageProperties.GIFLoopCount] = new NSString("0"); //options.GifDictionary[ImageIO.CGImageProperties.GIFHasGlobalColorMap] = new NSString("true"); using (var destintation = CGImageDestination.Create(mutableData, MobileCoreServices.UTType.GIF, decoded.AnimatedImages.Length, fileOptions)) { for (var i = 0; i < decoded.AnimatedImages.Length; i++) { var options = new CGImageDestinationOptions { GifDictionary = new NSMutableDictionary() }; options.GifDictionary[ImageIO.CGImageProperties.GIFUnclampedDelayTime] = new NSString(decoded.AnimatedImages[i].Delay.ToString()); destintation.AddImage(decoded.AnimatedImages[i].Image.CGImage, options); } destintation.Close(); } result = new PImage(mutableData); // TODO I really don't know why representations count is 1, anyone? // var test = result.Representations(); } #endif } else { result = decoded.Image; } return(Task.FromResult(result)); }
private async Task <DataResolverResult> ResolveFromNamedResourceAsync(string fileName, string identifier, TaskParameter parameters, CancellationToken token) { PImage image = null; try { #if __IOS__ || __TVOS__ await ImageService.Instance.Config.MainThreadDispatcher.PostAsync(() => image = PImage.FromBundle(identifier)).ConfigureAwait(false); #elif __MACOS__ await ImageService.Instance.Config.MainThreadDispatcher.PostAsync(() => image = PImage.ImageNamed(identifier)).ConfigureAwait(false); #endif } catch { } if (image == null && fileName != identifier) { try { #if __IOS__ || __TVOS__ await ImageService.Instance.Config.MainThreadDispatcher.PostAsync(() => image = PImage.FromBundle(fileName)).ConfigureAwait(false); #elif __MACOS__ await ImageService.Instance.Config.MainThreadDispatcher.PostAsync(() => image = PImage.ImageNamed(fileName)).ConfigureAwait(false); #endif } catch { } } if (image != null) { token.ThrowIfCancellationRequested(); var imageInformation = new ImageInformation(); imageInformation.SetPath(identifier); imageInformation.SetFilePath(null); var container = new DecodedImage <object>() { Image = image }; var result = new DataResolverResult(container, LoadingResult.CompiledResource, imageInformation); return(result); } return(null); }
protected override async Task <PImage> TransformAsync(PImage bitmap, IList <ITransformation> transformations, string path, ImageSource source, bool isPlaceholder) { await _decodingLock.WaitAsync(CancellationTokenSource.Token).ConfigureAwait(false); // Applying transformations is both CPU and memory intensive ThrowIfCancellationRequested(); try { foreach (var transformation in transformations) { ThrowIfCancellationRequested(); var old = bitmap; try { var bitmapHolder = transformation.Transform(new BitmapHolder(bitmap), path, source, isPlaceholder, Key); bitmap = bitmapHolder.ToNative(); } catch (Exception ex) { Logger.Error(string.Format("Transformation failed: {0}", transformation.Key), ex); throw; } finally { // Transformation succeeded, so garbage the source if (old != null && old.Handle != IntPtr.Zero && old != bitmap && old.Handle != bitmap.Handle) { old.TryDispose(); } } } } finally { _decodingLock.Release(); } return(bitmap); }
protected override Task <PImage> GenerateImageFromDecoderContainerAsync(IDecodedImage <PImage> decoded, ImageInformation imageInformation, bool isPlaceholder) { PImage result; if (decoded.IsAnimated) { #if __IOS__ result = PImage.CreateAnimatedImage(decoded.AnimatedImages .Select(v => v.Image) .Where(v => v?.CGImage != null).ToArray(), decoded.AnimatedImages.Sum(v => v.Delay) / 100.0); #elif __MACOS__ using (var mutableData = NSMutableData.Create()) { using (var destintation = CGImageDestination.Create(mutableData, MobileCoreServices.UTType.GIF, decoded.AnimatedImages.Length)) { for (int i = 0; i < decoded.AnimatedImages.Length; i++) { var options = new CGImageDestinationOptions(); options.GifDictionary = new NSMutableDictionary(); options.GifDictionary[ImageIO.CGImageProperties.GIFDelayTime] = NSNumber.FromDouble(decoded.AnimatedImages[i].Delay / 100.0d); destintation.AddImage(decoded.AnimatedImages[i].Image.CGImage, options); } destintation.Close(); } // TODO I really don't know why it's not working. Anyone? result = new PImage(mutableData); } #endif } else { result = decoded.Image; } return(Task.FromResult(result)); }
public Task <IBitmap> LoadFromResource(string source, float?desiredWidth, float?desiredHeight) { var tcs = new TaskCompletionSource <IBitmap>(); UIApplication.SharedApplication.InvokeOnMainThread(() => { try { #if UIKIT var bitmap = UIImage.FromBundle(source); #else var bitmap = UIImage.ImageNamed(source); #endif if (bitmap == null) { throw new Exception("Failed to load image from resource: " + source); } tcs.TrySetResult(new CocoaBitmap(bitmap)); } catch (Exception ex) { tcs.TrySetException(ex); } }); return(tcs.Task); }
protected virtual PImage Transform(PImage sourceBitmap) { return(null); }
public virtual async Task <Tuple <Stream, LoadingResult, ImageInformation> > Resolve(string identifier, TaskParameter parameters, CancellationToken token) { NSBundle bundle = null; var filename = Path.GetFileNameWithoutExtension(identifier); var tmpPath = Path.GetDirectoryName(identifier).Trim('/'); var filenamePath = string.IsNullOrWhiteSpace(tmpPath) ? null : tmpPath + "/"; foreach (var fileType in fileTypes) { string file = null; var extension = Path.HasExtension(identifier) ? Path.GetExtension(identifier) : string.IsNullOrWhiteSpace(fileType) ? string.Empty : "." + fileType; token.ThrowIfCancellationRequested(); int scale = (int)ScaleHelper.Scale; if (scale > 1) { while (scale > 1) { token.ThrowIfCancellationRequested(); var tmpFile = string.Format("{0}@{1}x{2}", filename, scale, extension); bundle = NSBundle._AllBundles.FirstOrDefault(bu => { var path = string.IsNullOrWhiteSpace(filenamePath) ? bu.PathForResource(tmpFile, null) : bu.PathForResource(tmpFile, null, filenamePath); return(!string.IsNullOrWhiteSpace(path)); }); if (bundle != null) { file = tmpFile; break; } scale--; } } token.ThrowIfCancellationRequested(); if (file == null) { var tmpFile = string.Format(filename + extension); file = tmpFile; bundle = NSBundle._AllBundles.FirstOrDefault(bu => { var path = string.IsNullOrWhiteSpace(filenamePath) ? bu.PathForResource(tmpFile, null) : bu.PathForResource(tmpFile, null, filenamePath); return(!string.IsNullOrWhiteSpace(path)); }); } token.ThrowIfCancellationRequested(); if (bundle != null) { string path = !string.IsNullOrEmpty(filenamePath) ? bundle.PathForResource(file, null, filenamePath) : bundle.PathForResource(file, null); var stream = FileStore.GetInputStream(path, true); var imageInformation = new ImageInformation(); imageInformation.SetPath(identifier); imageInformation.SetFilePath(path); return(new Tuple <Stream, LoadingResult, ImageInformation>( stream, LoadingResult.CompiledResource, imageInformation)); } token.ThrowIfCancellationRequested(); if (string.IsNullOrEmpty(fileType)) { //Asset catalog bool tryAssetsCatalog = true; #if __IOS__ if (!UIDevice.CurrentDevice.CheckSystemVersion(9, 0)) { tryAssetsCatalog = false; } #endif if (tryAssetsCatalog) { NSDataAsset asset = null; try { await ImageService.Instance.Config.MainThreadDispatcher.PostAsync(() => asset = new NSDataAsset(filename)).ConfigureAwait(false); } catch (Exception) { } if (asset != null) { token.ThrowIfCancellationRequested(); var stream = asset.Data?.AsStream(); var imageInformation = new ImageInformation(); imageInformation.SetPath(identifier); imageInformation.SetFilePath(null); return(new Tuple <Stream, LoadingResult, ImageInformation>( stream, LoadingResult.CompiledResource, imageInformation)); } } PImage image = null; try { #if __IOS__ await ImageService.Instance.Config.MainThreadDispatcher.PostAsync(() => image = PImage.FromBundle(filename)).ConfigureAwait(false); #elif __MACOS__ await ImageService.Instance.Config.MainThreadDispatcher.PostAsync(() => image = NSImage.ImageNamed(filename)).ConfigureAwait(false); #endif } catch (Exception) { } if (image != null) { token.ThrowIfCancellationRequested(); var stream = image.AsPngStream(); var imageInformation = new ImageInformation(); imageInformation.SetPath(identifier); imageInformation.SetFilePath(null); return(new Tuple <Stream, LoadingResult, ImageInformation>( stream, LoadingResult.CompiledResource, imageInformation)); } } } throw new FileNotFoundException(identifier); }
public static nuint GetMemorySize(this PImage image) { return((nuint)(image.CGImage.BytesPerRow * image.CGImage.Height)); }
protected async override Task <PImage> GenerateImageAsync(string path, ImageSource source, Stream imageData, ImageInformation imageInformation, bool enableTransformations, bool isPlaceholder) { PImage imageIn = null; if (imageData == null) { throw new ArgumentNullException(nameof(imageData)); } ThrowIfCancellationRequested(); try { int downsampleWidth = Parameters.DownSampleSize?.Item1 ?? 0; int downsampleHeight = Parameters.DownSampleSize?.Item2 ?? 0; bool allowUpscale = Parameters.AllowUpscale ?? Configuration.AllowUpscale; if (Parameters.DownSampleUseDipUnits) { downsampleWidth = downsampleWidth.PointsToPixels(); downsampleHeight = downsampleHeight.PointsToPixels(); } // Special case to handle WebP decoding on iOS if (source != ImageSource.Stream && imageInformation.Type == ImageInformation.ImageType.WEBP) { #if __IOS__ await _webpLock.WaitAsync(CancellationTokenSource.Token).ConfigureAwait(false); ThrowIfCancellationRequested(); try { var decoder = _webpDecoder as WebP.Touch.WebPCodec; if (decoder == null) { decoder = new WebP.Touch.WebPCodec(); _webpDecoder = decoder; } var decodedWebP = decoder.Decode(imageData); //TODO Add WebP images downsampling! imageIn = decodedWebP; } finally { _webpLock.Release(); } #else throw new NotImplementedException(); #endif } else { var nsdata = NSData.FromStream(imageData); imageIn = nsdata.ToImage(new CoreGraphics.CGSize(downsampleWidth, downsampleHeight), ScaleHelper.Scale, Configuration, Parameters, NSDataExtensions.RCTResizeMode.ScaleAspectFill, imageInformation, allowUpscale); } } finally { imageData.TryDispose(); } ThrowIfCancellationRequested(); if (enableTransformations && Parameters.Transformations != null && Parameters.Transformations.Count > 0) { var transformations = Parameters.Transformations.ToList(); await _decodingLock.WaitAsync(CancellationTokenSource.Token).ConfigureAwait(false); // Applying transformations is both CPU and memory intensive ThrowIfCancellationRequested(); try { bool isAnimation = false; #if __IOS__ if (imageIn.Images != null) { isAnimation = true; } #endif if (!isAnimation) { foreach (var transformation in transformations) { ThrowIfCancellationRequested(); var old = imageIn; try { var bitmapHolder = transformation.Transform(new BitmapHolder(imageIn), path, source, isPlaceholder, Key); imageIn = bitmapHolder.ToNative(); } catch (Exception ex) { Logger.Error(string.Format("Transformation failed: {0}", transformation.Key), ex); throw; } finally { if (old != null && old != imageIn && old.Handle != imageIn.Handle) { old.TryDispose(); } } } } else { // no animted image support for mac implemented #if __IOS__ var animatedImages = imageIn.Images.ToArray(); for (int i = 0; i < animatedImages.Length; i++) { var tempImage = animatedImages[i]; if (tempImage.CGImage == null) { continue; } foreach (var transformation in transformations) { ThrowIfCancellationRequested(); var old = tempImage; try { var bitmapHolder = transformation.Transform(new BitmapHolder(tempImage), path, source, isPlaceholder, Key); tempImage = bitmapHolder.ToNative(); } catch (Exception ex) { Logger.Error(string.Format("Transformation failed: {0}", transformation.Key), ex); throw; } finally { if (old != null && old != tempImage && old.Handle != tempImage.Handle) { old.TryDispose(); } } } animatedImages[i] = tempImage; } var oldImageIn = imageIn; imageIn = PImage.CreateAnimatedImage(animatedImages.Where(v => v.CGImage != null).ToArray(), imageIn.Duration); oldImageIn.TryDispose(); #endif } } finally { _decodingLock.Release(); } } return(imageIn); }
public BitmapHolder(PImage bitmap) { NativeBitmap = bitmap; }
/// <summary> /// Initializes a new instance of the <see cref="CocoaBitmap"/> class. /// </summary> /// <param name="inner">The native image we are wrapping.</param> public CocoaBitmap(UIImage inner) { _inner = inner; }
protected virtual PImage Transform(PImage sourceBitmap, string path, ImageSource source, bool isPlaceholder, string key) { return(sourceBitmap); }
public CocoaBitmap(UIImage inner) { this.inner = inner; }
public static PImage ResizeUIImage(this PImage image, double desiredWidth, double desiredHeight, InterpolationMode interpolationMode) { var widthRatio = desiredWidth / image.Size.Width; var heightRatio = desiredHeight / image.Size.Height; var scaleRatio = Math.Min(widthRatio, heightRatio); if (Math.Abs(desiredWidth) < double.Epsilon) { scaleRatio = heightRatio; } if (Math.Abs(desiredHeight) < double.Epsilon) { scaleRatio = widthRatio; } var aspectWidth = image.Size.Width * scaleRatio; var aspectHeight = image.Size.Height * scaleRatio; var newSize = new CGSize(aspectWidth, aspectHeight); #if __MACOS__ var resizedImage = new PImage(newSize); resizedImage.LockFocus(); image.Draw(new CGRect(CGPoint.Empty, newSize), CGRect.Empty, NSCompositingOperation.SourceOver, 1.0f); resizedImage.UnlockFocus(); return(resizedImage); #elif __IOS__ || __TVOS__ UIGraphics.BeginImageContextWithOptions(newSize, false, 0); try { image.Draw(new CGRect((nfloat)0.0, (nfloat)0.0, newSize.Width, newSize.Height)); using (var context = UIGraphics.GetCurrentContext()) { if (interpolationMode == InterpolationMode.None) { context.InterpolationQuality = CGInterpolationQuality.None; } else if (interpolationMode == InterpolationMode.Low) { context.InterpolationQuality = CGInterpolationQuality.Low; } else if (interpolationMode == InterpolationMode.Medium) { context.InterpolationQuality = CGInterpolationQuality.Medium; } else if (interpolationMode == InterpolationMode.High) { context.InterpolationQuality = CGInterpolationQuality.High; } else { context.InterpolationQuality = CGInterpolationQuality.Low; } var resizedImage = UIGraphics.GetImageFromCurrentImageContext(); return(resizedImage); } } finally { UIGraphics.EndImageContext(); image.TryDispose(); } #endif }
public override void Set(IImageLoaderTask task, PImage image, bool animated) { if (task == null || task.IsCancelled) { return; } var control = Control; if (control == null) { return; } #if __MACOS__ if (control.Image == image) { return; } #elif __IOS__ if (control.Image == image && (control.Image?.Images == null || control.Image.Images.Length <= 1)) { return; } #endif var parameters = task.Parameters; if (animated) { #if __MACOS__ // no animation support on Mac. NSImageView does not support animation like UIImageView does control.Image = image; #elif __IOS__ // fade animation double fadeDuration = (double)((parameters.FadeAnimationDuration.HasValue ? parameters.FadeAnimationDuration.Value : ImageService.Instance.Config.FadeAnimationDuration)) / 1000; UIView.Transition(control, fadeDuration, UIViewAnimationOptions.TransitionCrossDissolve | UIViewAnimationOptions.BeginFromCurrentState, () => { if (control.Image?.Images != null && control.Image.Images.Length > 1) { control.Image = null; } control.Image = image; }, () => { }); #endif } else { #if __IOS__ if (control.Image?.Images != null && control.Image.Images.Length > 1) { control.Image = null; } #endif control.Image = image; } }