private BitmapEditState CopyBitmapEditState(BitmapEditState original) { return(new BitmapEditState() { Flip = original.Flip, Proportions = original.Proportions, Rectangle = original.Rectangle, Rotation = original.Rotation, Strokes = original.Strokes }); }
public static async Task <ImageSource> CropAndPreviewAsync(IRandomAccessStream imageStream, BitmapEditState editState) { var decoder = await BitmapDecoder.CreateAsync(imageStream); var cropWidth = (double)decoder.PixelWidth; var cropHeight = (double)decoder.PixelHeight; if (decoder.PixelWidth > 1280 || decoder.PixelHeight > 1280) { double ratioX = 1280d / cropWidth; double ratioY = 1280d / cropHeight; double ratio = Math.Min(ratioX, ratioY); cropWidth *= ratio; cropHeight *= ratio; } var cropRectangle = new Rect( editState.Rectangle.X * decoder.PixelWidth, editState.Rectangle.Y * decoder.PixelHeight, editState.Rectangle.Width * decoder.PixelWidth, editState.Rectangle.Height * decoder.PixelHeight); if (editState.Rotation != BitmapRotation.None) { cropRectangle = RotateArea(cropRectangle, decoder.PixelWidth, decoder.PixelHeight, (int)editState.Rotation); } if (editState.Flip == BitmapFlip.Horizontal) { cropRectangle = FlipArea(cropRectangle, decoder.PixelWidth); } var(scaledCrop, scaledSize) = Scale(cropRectangle, new Size(decoder.PixelWidth, decoder.PixelHeight), new Size(cropWidth, cropHeight), 1280, 0); var bounds = new BitmapBounds(); bounds.X = (uint)scaledCrop.X; bounds.Y = (uint)scaledCrop.Y; bounds.Width = (uint)scaledCrop.Width; bounds.Height = (uint)scaledCrop.Height; var transform = new BitmapTransform(); transform.ScaledWidth = (uint)scaledSize.Width; transform.ScaledHeight = (uint)scaledSize.Height; transform.Bounds = bounds; transform.InterpolationMode = BitmapInterpolationMode.Linear; transform.Rotation = editState.Rotation; transform.Flip = editState.Flip; var pixelData = await decoder.GetSoftwareBitmapAsync(decoder.BitmapPixelFormat, BitmapAlphaMode.Premultiplied, transform, ExifOrientationMode.RespectExifOrientation, ColorManagementMode.DoNotColorManage); if (editState.Strokes != null) { var stream = await DrawStrokesAsync(pixelData, editState.Strokes, editState.Rectangle, editState.Rotation, editState.Flip); var bitmapImage = new BitmapImage(); await bitmapImage.SetSourceAsync(stream); return(bitmapImage); } else { var bitmapImage = new SoftwareBitmapSource(); await bitmapImage.SetBitmapAsync(pixelData); return(bitmapImage); } }
public static async Task <ImageSource> CropAndPreviewAsync(StorageFile sourceFile, BitmapEditState editState) { if (sourceFile.ContentType.Equals("video/mp4")) { var props = await sourceFile.Properties.GetVideoPropertiesAsync(); var composition = new MediaComposition(); var clip = await MediaClip.CreateFromFileAsync(sourceFile); composition.Clips.Add(clip); using (var imageStream = await composition.GetThumbnailAsync(TimeSpan.Zero, (int)props.GetWidth(), (int)props.GetHeight(), VideoFramePrecision.NearestKeyFrame)) { return(await CropAndPreviewAsync(imageStream, editState)); } } using (var imageStream = await sourceFile.OpenReadAsync()) { return(await CropAndPreviewAsync(imageStream, editState)); } }
public static async Task <(int Width, int Height)> GetScaleAsync(StorageFile file, int requestedMinSide = 1280, BitmapEditState editState = null) { var props = await file.Properties.GetImagePropertiesAsync(); var width = props.Width; var height = props.Height; if (editState?.Rectangle is Rect crop) { width = (uint)(crop.Width * props.Width); height = (uint)(crop.Height * props.Height); } if (width > requestedMinSide || height > requestedMinSide) { double ratioX = (double)requestedMinSide / width; double ratioY = (double)requestedMinSide / height; double ratio = Math.Min(ratioX, ratioY); if (editState != null && editState.Rotation is BitmapRotation.Clockwise90Degrees or BitmapRotation.Clockwise270Degrees) { return((int)(height * ratio), (int)(width * ratio)); } return((int)(width * ratio), (int)(height * ratio)); } if (editState != null && editState.Rotation is BitmapRotation.Clockwise90Degrees or BitmapRotation.Clockwise270Degrees) { return((int)height, (int)width); } return((int)width, (int)height); }
public async Task <InputMessageFactory> CreatePhotoAsync(StorageFile file, bool asFile, int ttl = 0, BitmapEditState editState = null) { try { using (var stream = await file.OpenReadAsync()) { var decoder = await BitmapDecoder.CreateAsync(stream); if (decoder.FrameCount > 1) { asFile = true; } } } catch { asFile = true; } var size = await ImageHelper.GetScaleAsync(file, editState : editState); var generated = await file.ToGeneratedAsync(asFile?ConversionType.Copy : ConversionType.Compress, editState != null?JsonConvert.SerializeObject(editState) : null); var thumbnail = default(InputThumbnail); if (asFile) { return(new InputMessageFactory { InputFile = generated, Type = new FileTypeDocument(), Delegate = (inputFile, caption) => new InputMessageDocument(inputFile, thumbnail, false, caption) }); } return(new InputMessageFactory { InputFile = generated, Type = new FileTypePhoto(), Delegate = (inputFile, caption) => new InputMessagePhoto(generated, thumbnail, new int[0], size.Width, size.Height, caption, ttl) }); }
public EditMediaPopup(StorageMedia media, ImageCropperMask mask = ImageCropperMask.Rectangle, bool ttl = false) { InitializeComponent(); Canvas.Strokes = media.EditState.Strokes; Cropper.SetMask(mask); if (mask == ImageCropperMask.Ellipse) { _hasMessageContext = false; media.EditState.Proportions = BitmapProportions.Square; } Cropper.SetProportions(media.EditState.Proportions); _file = media.File; _media = media; _originalMediaEditState = CopyBitmapEditState(media.EditState); Loaded += async(s, args) => { await Cropper.SetSourceAsync(media.File, media.EditState.Rotation, media.EditState.Flip, media.EditState.Proportions, media.EditState.Rectangle); if (!_hasMessageContext) //TODO: Fix mask bug, remove hack (#2017 references mask position) { await Cropper.SetSourceAsync(_media.File, _media.EditState.Rotation, _media.EditState.Flip, _media.EditState.Proportions, _media.EditState.Rectangle); Cropper.SetProportions(_media.EditState.Proportions); } Cropper.IsCropEnabled = !_hasMessageContext && _media.IsVideo; }; Unloaded += (s, args) => { Media.Source = null; }; #region Init UI if (mask == ImageCropperMask.Ellipse && string.Equals(media.File.FileType, ".mp4", StringComparison.OrdinalIgnoreCase)) { FindName(nameof(TrimToolbar)); TrimToolbar.Visibility = Visibility.Visible; BasicToolbar.Visibility = Visibility.Collapsed; SeparatorLeft.Visibility = Visibility.Collapsed; SeparatorRight.Visibility = Visibility.Collapsed; InitializeVideo(media.File); } if (_media is StorageVideo video) { _originalVideoCompression = video.Compression; _originalVideoIsMuted = video.IsMuted; Mute.IsChecked = video.IsMuted; Mute.Visibility = Visibility.Visible; Compress.IsChecked = video.Compression != video.MaxCompression; Compress.Visibility = video.CanCompress ? Visibility.Visible : Visibility.Collapsed; if (video.CanCompress) { Compress.Glyph = new CompressionToGlyphConverter().Convert(video.Compression, typeof(string), null, video.MaxCompression.ToString()).ToString(); Compress.CheckedGlyph = Compress.Glyph; Compress.IsChecked = video.Compression != video.MaxCompression; } } else { Mute.Visibility = Visibility.Collapsed; Compress.Visibility = Visibility.Collapsed; } Crop.Visibility = _media is StoragePhoto ? Visibility.Visible : Visibility.Collapsed; Draw.Visibility = Crop.Visibility; Ttl.Visibility = ttl ? Visibility.Visible : Visibility.Collapsed; Ttl.IsChecked = _media.Ttl > 0; if (_media.EditState is BitmapEditState editSate) { Crop.IsChecked = editSate.Proportions != BitmapProportions.Custom || editSate.Flip != BitmapFlip.None || editSate.Rotation != BitmapRotation.None || (!editSate.Rectangle.IsEmpty && (editSate.Rectangle.X > 0 || editSate.Rectangle.Y > 0 || Math.Abs(editSate.Rectangle.Width - 1) > 0.1f || Math.Abs(editSate.Rectangle.Height - 1) > 0.1f)); Draw.IsChecked = editSate.Strokes != null && editSate.Strokes.Count > 0; } else { Crop.IsChecked = false; Draw.IsChecked = false; } if (_hasMessageContext) { if (!string.IsNullOrWhiteSpace(media.Caption?.Text)) { CaptionInput.SetText(media.Caption); } } else { CaptionInput.Visibility = Visibility.Collapsed; } #endregion }