/// <summary> /// Converts a PhotoOrientation value into a human readable string. /// The text is adapted from the EXIF specification. /// Note that PhotoOrientation uses a counterclockwise convention, /// while the EXIF spec uses a clockwise convention. /// </summary> public static string GetOrientationString(PhotoOrientation input) { switch (input) { case PhotoOrientation.Normal: return "No rotation"; case PhotoOrientation.FlipHorizontal: return "Flip horizontally"; case PhotoOrientation.Rotate180: return "Rotate 180˚ clockwise"; case PhotoOrientation.FlipVertical: return "Flip vertically"; case PhotoOrientation.Transpose: return "Rotate 270˚ clockwise, then flip horizontally"; case PhotoOrientation.Rotate270: return "Rotate 90˚ clockwise"; case PhotoOrientation.Transverse: return "Rotate 90˚ clockwise, then flip horizontally"; case PhotoOrientation.Rotate90: return "Rotate 270˚ clockwise"; case PhotoOrientation.Unspecified: default: return "Unspecified"; } }
/// <summary> /// Clears all of the state that is stored in memory and in the UI. /// </summary> private void ResetSessionState() { m_fileToken = null; m_displayHeightNonScaled = 0; m_displayWidthNonScaled = 0; m_scaleFactor = 1; m_userRotation = PhotoOrientation.Normal; m_exifOrientation = PhotoOrientation.Normal; m_disableExifOrientation = false; RotateLeftButton.IsEnabled = false; RotateRightButton.IsEnabled = false; SaveButton.IsEnabled = false; SaveAsButton.IsEnabled = false; CloseButton.IsEnabled = false; PreviewImage.Source = null; m_transform.CenterX = ImageViewbox.Width / 2; m_transform.CenterY = ImageViewbox.Height / 2; ImageViewbox.RenderTransform = m_transform; UpdateImageRotation(PhotoOrientation.Normal); ScaleTextblock.Text = ""; ScaleSlider.Value = 100; ScaleSlider.IsEnabled = false; HeightTextblock.Text = ""; WidthTextblock.Text = ""; UserRotationTextblock.Text = ""; ExifOrientationTextblock.Text = ""; }
/// <summary> /// Counterpart to ConvertToPhotoOrientation(ushort input), maps PhotoOrientation enum /// values to an unsigned 16-bit integer representing the EXIF orientation flag. /// </summary> public static ushort ConvertToExifOrientationFlag(PhotoOrientation input) { switch (input) { case PhotoOrientation.Normal: return(1); case PhotoOrientation.FlipHorizontal: return(2); case PhotoOrientation.Rotate180: return(3); case PhotoOrientation.FlipVertical: return(4); case PhotoOrientation.Transpose: return(5); case PhotoOrientation.Rotate270: return(6); case PhotoOrientation.Transverse: return(7); case PhotoOrientation.Rotate90: return(8); default: return(1); } }
private static async Task CheckForFaces(IRandomAccessStream stream, PhotoOrientation photoOrientation) { try { using (var inputStream = stream) { var decoder = await BitmapDecoder.CreateAsync(inputStream); using (var inmem = new InMemoryRandomAccessStream()) { var encoder = await BitmapEncoder.CreateForTranscodingAsync(inmem, decoder); var properties = new BitmapPropertySet { { "System.Photo.Orientation", new BitmapTypedValue(photoOrientation, PropertyType.UInt16) } }; await encoder.BitmapProperties.SetPropertiesAsync(properties); await encoder.FlushAsync(); var subscriptionKey = "6b12f0c9eacd48ceaa3a26dd051677ae"; var faceServiceClient = new FaceServiceClient(subscriptionKey); Face[] faces = await faceServiceClient.DetectAsync(inmem.AsStream(), false, true, new FaceAttributeType[] { FaceAttributeType.Gender, FaceAttributeType.Age, FaceAttributeType.Smile, FaceAttributeType.Glasses }); Debug.WriteLine("has faces?"); } } } catch (Exception ex) { Debug.WriteLine(ex); } }
/// <summary> /// Converts a PhotoOrientation value into a human-readable string. /// The text is adapted from the EXIF specification. /// Note that PhotoOrientation uses a counterclockwise convention, /// while the EXIF spec uses a clockwise convention. /// </summary> public static string GetOrientationString(PhotoOrientation input) { switch (input) { case PhotoOrientation.Normal: return("No rotation"); case PhotoOrientation.FlipHorizontal: return("Flip horizontally"); case PhotoOrientation.Rotate180: return("Rotate 180˚ clockwise"); case PhotoOrientation.FlipVertical: return("Flip vertically"); case PhotoOrientation.Transpose: return("Rotate 270˚ clockwise, then flip horizontally"); case PhotoOrientation.Rotate270: return("Rotate 90˚ clockwise"); case PhotoOrientation.Transverse: return("Rotate 90˚ clockwise, then flip horizontally"); case PhotoOrientation.Rotate90: return("Rotate 270˚ clockwise"); case PhotoOrientation.Unspecified: default: return("Unspecified"); } }
/// <summary> /// Reads the file token and image transform variables from the persisted state and /// restores the UI. /// </summary> private async void RestoreDataFromPersistedState() { try { rootPage.NotifyUser("Loading image file from persisted state...", NotifyType.StatusMessage); m_fileToken = (string)m_localSettings["scenario2FileToken"]; m_displayWidthNonScaled = (uint)m_localSettings["scenario2Width"]; m_displayHeightNonScaled = (uint)m_localSettings["scenario2Height"]; m_scaleFactor = (double)m_localSettings["scenario2Scale"]; PhotoOrientation desiredOrientation = Helpers.ConvertToPhotoOrientation((ushort)m_localSettings["scenario2UserRotation"]); m_exifOrientation = Helpers.ConvertToPhotoOrientation((ushort)m_localSettings["scenario2ExifOrientation"]); m_disableExifOrientation = (bool)m_localSettings["scenario2DisableExif"]; // Display the image in the UI. StorageFile file = await m_futureAccess.GetFileAsync(m_fileToken); BitmapImage src = new BitmapImage(); using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.Read)) { await src.SetSourceAsync(stream); } PreviewImage.Source = src; AutomationProperties.SetName(PreviewImage, file.Name); // Display the image dimensions and transformation state in the UI. ExifOrientationTextblock.Text = Helpers.GetOrientationString(m_exifOrientation); ScaleSlider.Value = m_scaleFactor * 100; UpdateImageDimensionsUI(); // Restore the image tag's rotation transform. while (desiredOrientation != m_userRotation) { RotateRight_Click(null, null); } RotateRightButton.IsEnabled = true; RotateLeftButton.IsEnabled = true; SaveButton.IsEnabled = true; CloseButton.IsEnabled = true; SaveAsButton.IsEnabled = true; ScaleSlider.IsEnabled = true; rootPage.NotifyUser("Loaded image file from persisted state: " + file.Name, NotifyType.StatusMessage); } catch (Exception err) { rootPage.NotifyUser("Error: " + err.Message, NotifyType.ErrorMessage); ResetSessionState(); ResetPersistedState(); } }
/// <summary> /// When the user clicks Rotate Left, rotate the ImageViewbox by 90 degrees counterclockwise, /// and update the dimensions. /// </summary> private void RotateLeft_Click(object sender, RoutedEventArgs e) { m_userRotation = Helpers.Add90DegreesCCW(m_userRotation); // Swap width and height. uint temp = m_displayHeightNonScaled; m_displayHeightNonScaled = m_displayWidthNonScaled; m_displayWidthNonScaled = temp; UpdateImageDimensionsUI(); UpdateImageRotation(m_userRotation); }
/// <summary> /// Asynchronously attempts to get the oriented dimensions and EXIF orientation from the image file. /// Sets member variables instead of returning a value with the Task. /// </summary> /// <param name="file"></param> /// <returns></returns> private async Task GetImageInformationAsync(StorageFile file) { using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.Read)) { BitmapDecoder decoder = await BitmapDecoder.CreateAsync(stream); // The orientedPixelWidth and Height members provide the image dimensions // reflecting any EXIF orientation. m_displayHeightNonScaled = decoder.OrientedPixelHeight; m_displayWidthNonScaled = decoder.OrientedPixelWidth; try { // Property access using BitmapProperties is similar to using // Windows.Storage.FileProperties (see Scenario 1); BitmapProperties accepts // property keys such as "System.Photo.Orientation". // The EXIF orientation flag can be also be read using native metadata queries // such as "/app1/ifd/{ushort=274}" (JPEG) or "/ifd/{ushort=274}" (TIFF). string[] requestedProperties = { "System.Photo.Orientation" }; BitmapPropertySet retrievedProperties = await decoder.BitmapProperties.GetPropertiesAsync(requestedProperties); // Check to see if the property exists in the file. if (retrievedProperties.ContainsKey("System.Photo.Orientation")) { // EXIF orientation ("System.Photo.Orientation") is stored as a 16-bit unsigned integer. m_exifOrientation = Helpers.ConvertToPhotoOrientation( (ushort)retrievedProperties["System.Photo.Orientation"].Value ); } } catch (Exception err) { switch (err.HResult) { // If the file format does not support properties continue without applying EXIF orientation. case WINCODEC_ERR_UNSUPPORTEDOPERATION: case WINCODEC_ERR_PROPERTYNOTSUPPORTED: m_disableExifOrientation = true; break; default: throw err; } } } }
/// <summary> /// Converts a Windows.Storage.FileProperties.PhotoOrientation value into a /// Windows.Graphics.Imaging.BitmapRotation value. /// For PhotoOrientation values reflecting a flip/mirroring operation, returns "None"; /// therefore this is a potentially lossy transformation. /// Note that PhotoOrientation uses a counterclockwise convention, /// while BitmapRotation uses a clockwise convention. /// </summary> public static BitmapRotation ConvertToBitmapRotation(PhotoOrientation input) { switch (input) { case PhotoOrientation.Normal: return BitmapRotation.None; case PhotoOrientation.Rotate270: return BitmapRotation.Clockwise90Degrees; case PhotoOrientation.Rotate180: return BitmapRotation.Clockwise180Degrees; case PhotoOrientation.Rotate90: return BitmapRotation.Clockwise270Degrees; default: // Ignore any flip/mirrored values. return BitmapRotation.None; } }
/// <summary> /// "Adds" two PhotoOrientation values. For simplicity, does not handle any values with /// flip/mirroring; therefore this is a potentially lossy transformation. /// Note that PhotoOrientation uses a counterclockwise convention. /// </summary> public static PhotoOrientation AddPhotoOrientation(PhotoOrientation value1, PhotoOrientation value2) { switch (value2) { case PhotoOrientation.Rotate90: return(Add90DegreesCCW(value1)); case PhotoOrientation.Rotate180: return(Add90DegreesCCW(Add90DegreesCCW(value1))); case PhotoOrientation.Rotate270: return(Add90DegreesCW(value1)); case PhotoOrientation.Normal: default: // Ignore any values with flip/mirroring. return(value1); } }
/// <summary> /// Clear all of the state that is stored in memory and in the UI /// </summary> private async void ResetSessionState() { m_fileToken = null; m_displayHeightNonScaled = 0; m_displayWidthNonScaled = 0; m_scaleFactor = 1; m_userRotation = PhotoOrientation.Normal; m_exifOrientation = PhotoOrientation.Normal; m_disableExifOrientation = false; RotateLeftButton.IsEnabled = false; RotateRightButton.IsEnabled = false; SaveButton.IsEnabled = false; SaveAsButton.IsEnabled = false; CloseButton.IsEnabled = false; StorageFile placeholderImage = await Package.Current.InstalledLocation.GetFileAsync("Assets\\placeholder-sdk.png"); BitmapImage bitmapImage = new BitmapImage(); using (IRandomAccessStream stream = await placeholderImage.OpenAsync(FileAccessMode.Read)) { await bitmapImage.SetSourceAsync(stream); } Image1.Source = bitmapImage; AutomationProperties.SetName(Image1, "A placeholder image"); m_transform.CenterX = ImageViewbox.Width / 2; m_transform.CenterY = ImageViewbox.Height / 2; ImageViewbox.RenderTransform = m_transform; UpdateImageRotation(PhotoOrientation.Normal); ScaleTextblock.Text = ""; ScaleSlider.Value = 100; ScaleSlider.IsEnabled = false; HeightTextblock.Text = ""; WidthTextblock.Text = ""; UserRotationTextblock.Text = ""; ExifOrientationTextblock.Text = ""; }
/// <summary> /// Converts a Windows.Storage.FileProperties.PhotoOrientation value into a /// Windows.Graphics.Imaging.BitmapRotation value. /// For PhotoOrientation values reflecting a flip/mirroring operation, returns "None"; /// therefore this is a potentially lossy transformation. /// Note that PhotoOrientation uses a counterclockwise convention, /// while BitmapRotation uses a clockwise convention. /// </summary> public static BitmapRotation ConvertToBitmapRotation(PhotoOrientation input) { switch (input) { case PhotoOrientation.Normal: return(BitmapRotation.None); case PhotoOrientation.Rotate270: return(BitmapRotation.Clockwise90Degrees); case PhotoOrientation.Rotate180: return(BitmapRotation.Clockwise180Degrees); case PhotoOrientation.Rotate90: return(BitmapRotation.Clockwise270Degrees); default: // Ignore any flip/mirrored values. return(BitmapRotation.None); } }
/// <summary> /// "Add" 90 degrees counter-clockwise rotation to a PhotoOrientation value. /// For simplicity, does not handle any values with flip/mirroring; therefore this can be /// a lossy transformation. /// Note that PhotoOrientation uses a counterclockwise convention. /// </summary> public static PhotoOrientation Add90DegreesCCW(PhotoOrientation input) { switch (input) { case PhotoOrientation.Normal: return(PhotoOrientation.Rotate90); case PhotoOrientation.Rotate90: return(PhotoOrientation.Rotate180); case PhotoOrientation.Rotate180: return(PhotoOrientation.Rotate270); case PhotoOrientation.Rotate270: return(PhotoOrientation.Normal); default: // Ignore any values with flip/mirroring. return(PhotoOrientation.Unspecified); } }
private static async Task CapturePhotoAsync(IRandomAccessStream stream, PhotoOrientation photoOrientation) { using (var inputStream = stream) { var decoder = await BitmapDecoder.CreateAsync(inputStream); var file = await KnownFolders.PicturesLibrary.CreateFileAsync("SimplePhoto.jpeg", CreationCollisionOption.GenerateUniqueName); using (var outputStream = await file.OpenAsync(FileAccessMode.ReadWrite)) { var encoder = await BitmapEncoder.CreateForTranscodingAsync(outputStream, decoder); var properties = new BitmapPropertySet { { "System.Photo.Orientation", new BitmapTypedValue(photoOrientation, PropertyType.UInt16) } }; await encoder.BitmapProperties.SetPropertiesAsync(properties); await encoder.FlushAsync(); } } }
/// <summary> /// Sets the RotationTransform angle of the Image (technically, its parent Viewbox). /// </summary> private void UpdateImageRotation(PhotoOrientation rotation) { switch (rotation) { case PhotoOrientation.Rotate270: // Note that the PhotoOrientation enumeration uses a counterclockwise convention, // while the RotationTransform uses a clockwise convention. m_transform.Angle = 90; break; case PhotoOrientation.Rotate180: m_transform.Angle = 180; break; case PhotoOrientation.Rotate90: m_transform.Angle = 270; break; case PhotoOrientation.Normal: default: m_transform.Angle = 0; break; } }
private void UpdateImageRotation(PhotoOrientation rotation) { switch (rotation) { case PhotoOrientation.Rotate270: // Note that the PhotoOrientation enumeration uses a counterclockwise convention, // while the RotationTransform uses a clockwise convention. m_transform.Angle = 90; break; case PhotoOrientation.Rotate180: m_transform.Angle = 180; break; case PhotoOrientation.Rotate90: m_transform.Angle = 270; break; case PhotoOrientation.Normal: default: m_transform.Angle = 0; break; } }
private void rotateBtn_Click(object sender, RoutedEventArgs e) { if ((sender as Button).Equals(rotateBtn)) { rotateBtnText.Foreground = new SolidColorBrush(Color.FromArgb(255, 255, 168, 1)); rotateBtnImage.Source = new BitmapImage(new Uri("ms-appx:///Assets/MenuIco/icon 07 2.png")); rotateBtnTextRevert.Foreground = new SolidColorBrush(Color.FromArgb(255, 255, 255, 255)); rotateBtnImageRevert.Source = new BitmapImage(new Uri("ms-appx:///Assets/MenuIco/icon 08.png")); m_transform.CenterX = imagePanel.ActualWidth / 2; m_transform.CenterY = imagePanel.ActualHeight / 2; imagePanel.RenderTransform = m_transform; m_userRotation = Helpers.Add90DegreesCW(m_userRotation); //Swap width and height. int temp = m_displayHeightNonScaled; m_displayHeightNonScaled = m_displayWidthNonScaled; m_displayWidthNonScaled = temp; UpdateImageRotation(m_userRotation); } else { rotateBtnText.Foreground = new SolidColorBrush(Color.FromArgb(255, 255, 255, 255)); rotateBtnImage.Source = new BitmapImage(new Uri("ms-appx:///Assets/MenuIco/icon 07.png")); rotateBtnTextRevert.Foreground = new SolidColorBrush(Color.FromArgb(255, 255, 168, 1)); rotateBtnImageRevert.Source = new BitmapImage(new Uri("ms-appx:///Assets/MenuIco/icon 08 2.png")); m_transform.CenterX = imagePanel.ActualWidth / 2; m_transform.CenterY = imagePanel.ActualHeight / 2; imagePanel.RenderTransform = m_transform; m_userRotation = Helpers.Add90DegreesCCW(m_userRotation); // Swap width and height. int temp = m_displayHeightNonScaled; m_displayHeightNonScaled = m_displayWidthNonScaled; m_displayWidthNonScaled = temp; UpdateImageRotation(m_userRotation); } }
/// <summary> /// Applies the given orientation to a photo stream and saves it as a StorageFile /// </summary> /// <param name="stream">The photo stream</param> /// <param name="photoOrientation">The orientation metadata to apply to the photo</param> /// <returns></returns> private async Task <string> ReencodeAndSavePhotoAsync(IRandomAccessStream stream, PhotoOrientation photoOrientation) { using (var inputStream = stream) { var decoder = await BitmapDecoder.CreateAsync(inputStream); var file = await Package.Current.InstalledLocation.CreateFileAsync("4shot.jpeg", CreationCollisionOption.GenerateUniqueName); using (var outputStream = await file.OpenAsync(FileAccessMode.ReadWrite)) { var encoder = await BitmapEncoder.CreateForTranscodingAsync(outputStream, decoder); var properties = new BitmapPropertySet { { "System.Photo.Orientation", new BitmapTypedValue(photoOrientation, PropertyType.UInt16) } }; await encoder.BitmapProperties.SetPropertiesAsync(properties); await encoder.FlushAsync(); } SettingsHelper.SaveObjectToStorage("CurrentProfile", new Profile { Name = "Unknown", ImagePath = file.Path }); return(file.Path); } }
private async Task ReencodeAndSavePhotoAsync(IRandomAccessStream stream, string filename, PhotoOrientation photoOrientation) { using (var inputStream = stream) { var decoder = await BitmapDecoder.CreateAsync(inputStream); var file = await KnownFolders.PicturesLibrary.CreateFileAsync(filename, CreationCollisionOption.GenerateUniqueName); using (var outputStream = await file.OpenAsync(FileAccessMode.ReadWrite)) { var encoder = await BitmapEncoder.CreateForTranscodingAsync(outputStream, decoder); var properties = new BitmapPropertySet { { "System.Photo.Orientation", new BitmapTypedValue(photoOrientation, PropertyType.UInt16) } }; await encoder.BitmapProperties.SetPropertiesAsync(properties); await encoder.FlushAsync(); } } Functions.DisplayMessage((String)_resources["photoTaken"]); cameraButton.IsEnabled = true; }
private async Task DetectPhotoAsync(IRandomAccessStream stream, PhotoOrientation photoOrientation) { using (var inputStream = stream) { var decoder = await BitmapDecoder.CreateAsync(inputStream); var file = await KnownFolders.PicturesLibrary.CreateFileAsync("SimplePhoto.jpeg", CreationCollisionOption.GenerateUniqueName); using (var outputStream = new InMemoryRandomAccessStream()) { var encoder = await BitmapEncoder.CreateForTranscodingAsync(outputStream, decoder); var properties = new BitmapPropertySet { { "System.Photo.Orientation", new BitmapTypedValue(photoOrientation, PropertyType.UInt16) } }; await encoder.BitmapProperties.SetPropertiesAsync(properties); await encoder.FlushAsync(); var faces = await _instance.DetectAsync(outputStream.AsStream(), false, true, true, false); } } }
/// <summary> /// Asynchronously attempts to get the oriented dimensions and EXIF orientation from the image file. /// Sets member variables instead of returning a value with the Task. /// </summary> /// <param name="file"></param> /// <returns></returns> private async Task GetImageInformationAsync(StorageFile file) { using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.Read)) { BitmapDecoder decoder = await BitmapDecoder.CreateAsync(stream); // The orientedPixelWidth and Height members provide the image dimensions // reflecting any EXIF orientation. m_displayHeightNonScaled = decoder.OrientedPixelHeight; m_displayWidthNonScaled = decoder.OrientedPixelWidth; try { // Property access using BitmapProperties is similar to using // Windows.Storage.FileProperties (see Scenario 1); BitmapProperties accepts // property keys such as "System.Photo.Orientation". // The EXIF orientation flag can be also be read using native metadata queries // such as "/app1/ifd/{ushort=274}" (JPEG) or "/ifd/{ushort=274}" (TIFF). string[] requestedProperties = { "System.Photo.Orientation" }; BitmapPropertySet retrievedProperties = await decoder.BitmapProperties.GetPropertiesAsync(requestedProperties); // Check to see if the property exists in the file. if (retrievedProperties.ContainsKey("System.Photo.Orientation")) { // EXIF orientation ("System.Photo.Orientation") is stored as a 16-bit unsigned integer. m_exifOrientation = Helpers.ConvertToPhotoOrientation( (ushort) retrievedProperties["System.Photo.Orientation"].Value ); } } catch (Exception err) { switch (err.HResult) { // If the file format does not support properties continue without applying EXIF orientation. case WINCODEC_ERR_UNSUPPORTEDOPERATION: case WINCODEC_ERR_PROPERTYNOTSUPPORTED: m_disableExifOrientation = true; break; default: throw; } } } }
protected override void OnNavigatedTo(NavigationEventArgs e) { base.OnNavigatedTo(e); if (e.Parameter != null) { var param = e.Parameter; if (param.ToString().Equals((typeof(PictureListInfo)).ToString())) { PictureListInfo info = param as PictureListInfo; image.Source = info.picture; filePath = info.picturePath; this.info = info; } else if (param.ToString().Equals((typeof(PageNavigateParam)).ToString())) { isProjected = true; PageNavigateParam projectParam = param as PageNavigateParam; mainViewId = projectParam.MainViewId; //thisViewControl = projectParam.ProjectionViewPageControl; //mainDispatcher = projectParam.MainDispatcher; //thisViewControl.Released += ThisViewControl_Released; GLOABOALSTAGE stageProjected = projectParam.stage; if(stageProjected != GLOABOALSTAGE.EDITPAGE_INK) { monitorTimer = new DispatcherTimer(); monitorTimer.Interval = new TimeSpan(0, 0, 2); monitorTimer.Tick += MonitorTimer_Tick; monitorTimer.Start(); } switch (stageProjected) { case GLOABOALSTAGE.EDITPAGE_CROP: cropParam = projectParam.stageParam as CropStateParam; this.info = cropParam.PicInfo; filePath = info.picturePath; break; case GLOABOALSTAGE.EDITPAGE_ROTATE: RotateStateParam rotateParam = projectParam.stageParam as RotateStateParam; this.info = rotateParam.PicInfo; filePath = info.picturePath; stage = GLOABOALSTAGE.EDITPAGE_ROTATE; m_userRotation = rotateParam.UserRotation; break; case GLOABOALSTAGE.EDITPAGE_INK: InkStateParam inkParam = projectParam.stageParam as InkStateParam; this.info = inkParam.PicInfo; filePath = info.picturePath; stage = GLOABOALSTAGE.EDITPAGE_INK; //((App)App.Current).SyncStrokeEx(strokeMapping, true); ink.Visibility = Visibility.Visible; break; case GLOABOALSTAGE.EDITPAGE_TEXT: TextStateParam textParam = projectParam.stageParam as TextStateParam; this.info = textParam.PicInfo; filePath = info.picturePath; stage = GLOABOALSTAGE.EDITPAGE_TEXT; break; } } } }
///// <summary> ///// Attempts to find and return a device mounted on the panel specified, and on failure to find one it will return the first device listed ///// </summary> ///// <param name="desiredPanel">The desired panel on which the returned device should be mounted, if available</param> ///// <returns></returns> //public static async Task<DeviceInformation> FindCameraDeviceByPanelAsync(Windows.Devices.Enumeration.Panel desiredPanel) //{ // // Get available devices for capturing pictures // var allVideoDevices = await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture); // // Get the desired camera by panel // DeviceInformation desiredDevice = allVideoDevices.FirstOrDefault(x => x.EnclosureLocation != null && x.EnclosureLocation.Panel == desiredPanel); // // If there is no device mounted on the desired panel, return the first device found // return desiredDevice ?? allVideoDevices.FirstOrDefault(); //} /// <summary> /// Applies the given orientation to a photo stream and saves it as a StorageFile /// </summary> /// <param name="inputStream">The photo stream</param> /// <param name="photoOrientation">The orientation metadata to apply to the photo</param> /// <returns></returns> private async Task ReencodeAndSavePhotoAsync(IRandomAccessStream inputStream, PhotoOrientation photoOrientation) { try { // LOLLO this decoder already has 480 × 640. if i set a different size when capturing the pic, // this decoder will respect it. var decoder = await BitmapDecoder.CreateAsync(inputStream); //StorageFile file = await GetFileAsync(); using (var outputStream = await _file.OpenAsync(FileAccessMode.ReadWrite)) { var encoder = await BitmapEncoder.CreateForTranscodingAsync(outputStream, decoder); var bitmapProperties = new BitmapPropertySet { { "System.Photo.Orientation", new BitmapTypedValue(photoOrientation, PropertyType.UInt16) } }; await encoder.BitmapProperties.SetPropertiesAsync(bitmapProperties); await encoder.FlushAsync(); } } catch (Exception ex) { await Logger.AddAsync(ex.ToString(), Logger.ForegroundLogFilename); Debugger.Break(); } //finally //{ // //VM?.ForceEndShootAsync(); //} }
/// <summary> /// Counterpart to ConvertToPhotoOrientation(ushort input), maps PhotoOrientation enumeration /// values to an unsigned 16-bit integer representing the EXIF orientation flag. /// </summary> public static ushort ConvertToExifOrientationFlag(PhotoOrientation input) { switch (input) { case PhotoOrientation.Normal: return 1; case PhotoOrientation.FlipHorizontal: return 2; case PhotoOrientation.Rotate180: return 3; case PhotoOrientation.FlipVertical: return 4; case PhotoOrientation.Transpose: return 5; case PhotoOrientation.Rotate270: return 6; case PhotoOrientation.Transverse: return 7; case PhotoOrientation.Rotate90: return 8; default: return 1; } }
/// <summary> /// "Adds" two PhotoOrientation values. For simplicity, does not handle any values with /// flip/mirroring; therefore this is a potentially lossy transformation. /// Note that PhotoOrientation uses a counterclockwise convention. /// </summary> public static PhotoOrientation AddPhotoOrientation(PhotoOrientation value1, PhotoOrientation value2) { switch (value2) { case PhotoOrientation.Rotate90: return Add90DegreesCCW(value1); case PhotoOrientation.Rotate180: return Add90DegreesCCW(Add90DegreesCCW(value1)); case PhotoOrientation.Rotate270: return Add90DegreesCW(value1); case PhotoOrientation.Normal: default: // Ignore any values with flip/mirroring. return value1; } }
private static async Task <InMemoryRandomAccessStream> ReencodeAndSavePhotoAsync(IRandomAccessStream stream, PhotoOrientation photoOrientation) { using (var inputStream = stream) { var decoder = await BitmapDecoder.CreateAsync(inputStream); var memoryStream = new InMemoryRandomAccessStream(); var encoder = await BitmapEncoder.CreateForTranscodingAsync(memoryStream, decoder); var properties = new BitmapPropertySet { { "System.Photo.Orientation", new BitmapTypedValue(photoOrientation, PropertyType.UInt16) } }; await encoder.BitmapProperties.SetPropertiesAsync(properties); await encoder.FlushAsync(); return(memoryStream); } }
private async Task <string> ReencodeAndSavePhotoAsync(IRandomAccessStream stream, PhotoOrientation photoOrientation) { using (var inputStream = stream) { var decoder = await BitmapDecoder.CreateAsync(inputStream); var file = await ApplicationData.Current.LocalFolder.CreateFileAsync("photo.jpeg", CreationCollisionOption.GenerateUniqueName); using (var outputStream = await file.OpenAsync(FileAccessMode.ReadWrite)) { var encoder = await BitmapEncoder.CreateForTranscodingAsync(outputStream, decoder); var properties = new BitmapPropertySet { { "System.Photo.Orientation", new BitmapTypedValue(photoOrientation, PropertyType.UInt16) } }; await encoder.BitmapProperties.SetPropertiesAsync(properties); await encoder.FlushAsync(); } return(file.Path); } }
private void ResetSessionState() { m_displayHeightNonScaled = 0; m_displayWidthNonScaled = 0; m_userRotation = PhotoOrientation.Normal; m_transform.Angle = 0; }
/// <summary> /// Applies the given orientation to a photo stream and saves it as a StorageFile /// </summary> /// <param name="stream">The photo stream</param> /// <param name="file">The StorageFile in which the photo stream will be saved</param> /// <param name="photoOrientation">The orientation metadata to apply to the photo</param> /// <returns></returns> private static async Task ReencodeAndSavePhotoAsync(IRandomAccessStream stream, StorageFile file, PhotoOrientation photoOrientation) { using (var inputStream = stream) { var decoder = await BitmapDecoder.CreateAsync(inputStream); using (var outputStream = await file.OpenAsync(FileAccessMode.ReadWrite)) { var encoder = await BitmapEncoder.CreateForTranscodingAsync(outputStream, decoder); var properties = new BitmapPropertySet { { "System.Photo.Orientation", new BitmapTypedValue(photoOrientation, PropertyType.UInt16) } }; await encoder.BitmapProperties.SetPropertiesAsync(properties); await encoder.FlushAsync(); } } }
private async Task<IRandomAccessStream> ResizeStreamAsync(IRandomAccessStream stream, Size size, PhotoOrientation orientation) { var rotation = 0; switch (orientation) { case PhotoOrientation.Rotate180: { rotation = -180; }; break; case PhotoOrientation.Rotate270: { rotation = -270; }; break; case PhotoOrientation.Rotate90: { rotation = -90; }; break; } using (var resizedStream = new InMemoryRandomAccessStream()) { var buffer = new byte[stream.Size].AsBuffer(); stream.Seek(0); await stream.ReadAsync(buffer, buffer.Length, InputStreamOptions.None); var resizeConfiguration = new AutoResizeConfiguration( (uint)(size.Width * size.Height * 4 * 2), size, new Size(0, 0), AutoResizeMode.Automatic, 0.7, ColorSpace.Yuv420); buffer = await JpegTools.AutoResizeAsync(buffer, resizeConfiguration); await resizedStream.WriteAsync(buffer); await resizedStream.FlushAsync(); if (rotation != 0) { resizedStream.Seek(0); var filters = new List<IFilter>() { new RotationFilter(rotation) }; using (var source = new RandomAccessStreamImageSource(resizedStream)) using (var effect = new FilterEffect(source) { Filters = filters }) using (var renderer = new JpegRenderer(effect)) { buffer = await renderer.RenderAsync(); using (var rotatedResizedStream = new InMemoryRandomAccessStream()) { await rotatedResizedStream.WriteAsync(buffer); await rotatedResizedStream.FlushAsync(); return rotatedResizedStream.CloneStream(); } } } else { return resizedStream.CloneStream(); } } }
/// <summary> /// Clear all of the state that is stored in memory and in the UI /// </summary> private void ResetSessionState() { m_fileToken = null; m_displayHeightNonScaled = 0; m_displayWidthNonScaled = 0; m_scaleFactor = 1; m_userRotation = PhotoOrientation.Normal; m_exifOrientation = PhotoOrientation.Normal; m_disableExifOrientation = false; RotateLeftButton.IsEnabled = false; RotateRightButton.IsEnabled = false; SaveButton.IsEnabled = false; SaveAsButton.IsEnabled = false; CloseButton.IsEnabled = false; PreviewImage.Source = null; m_transform.CenterX = ImageViewbox.Width / 2; m_transform.CenterY = ImageViewbox.Height / 2; ImageViewbox.RenderTransform = m_transform; UpdateImageRotation(PhotoOrientation.Normal); ScaleTextblock.Text = ""; ScaleSlider.Value = 100; ScaleSlider.IsEnabled = false; HeightTextblock.Text = ""; WidthTextblock.Text = ""; UserRotationTextblock.Text = ""; ExifOrientationTextblock.Text = ""; }
/// <summary> /// Reads the file token and image transform variables from the persisted state and /// restores the UI. /// </summary> private async void RestoreDataFromPersistedState() { try { rootPage.NotifyUser("Loading image file from persisted state...", NotifyType.StatusMessage); m_fileToken = (string)m_localSettings["scenario2FileToken"]; m_displayWidthNonScaled = (uint)m_localSettings["scenario2Width"]; m_displayHeightNonScaled = (uint)m_localSettings["scenario2Height"]; m_scaleFactor = (double)m_localSettings["scenario2Scale"]; PhotoOrientation desiredOrientation = Helpers.ConvertToPhotoOrientation((ushort)m_localSettings["scenario2UserRotation"]); m_exifOrientation = Helpers.ConvertToPhotoOrientation((ushort)m_localSettings["scenario2ExifOrientation"]); m_disableExifOrientation = (bool)m_localSettings["scenario2DisableExif"]; // Display the image in the UI. StorageFile file = await m_futureAccess.GetFileAsync(m_fileToken); BitmapImage src = new BitmapImage(); using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.Read)) { await src.SetSourceAsync(stream); } Image1.Source = src; AutomationProperties.SetName(Image1, file.Name); // Display the image dimensions and transformation state in the UI. ExifOrientationTextblock.Text = Helpers.GetOrientationString(m_exifOrientation); ScaleSlider.Value = m_scaleFactor * 100; UpdateImageDimensionsUI(); // Restore the image tag's rotation transform. while (desiredOrientation != m_userRotation) { RotateRight_Click(null, null); } RotateRightButton.IsEnabled = true; RotateLeftButton.IsEnabled = true; SaveButton.IsEnabled = true; CloseButton.IsEnabled = true; SaveAsButton.IsEnabled = true; ScaleSlider.IsEnabled = true; rootPage.NotifyUser("Loaded image file from persisted state: " + file.Name, NotifyType.StatusMessage); } catch (Exception err) { rootPage.NotifyUser("Error: " + err.Message, NotifyType.ErrorMessage); ResetSessionState(); ResetPersistedState(); } }
/// <summary> /// "Add" 90 degrees counter-clockwise rotation to a PhotoOrientation value. /// For simplicity, does not handle any values with flip/mirroring; therefore this is a potentially /// lossy transformation. /// Note that PhotoOrientation uses a counterclockwise convention. /// </summary> public static PhotoOrientation Add90DegreesCCW(PhotoOrientation input) { switch (input) { case PhotoOrientation.Normal: return PhotoOrientation.Rotate90; case PhotoOrientation.Rotate90: return PhotoOrientation.Rotate180; case PhotoOrientation.Rotate180: return PhotoOrientation.Rotate270; case PhotoOrientation.Rotate270: return PhotoOrientation.Normal; default: // Ignore any values with flip/mirroring. return PhotoOrientation.Unspecified; } }
/// <summary> /// Applies the given orientation to a photo stream and saves it as a StorageFile /// </summary> /// <param name="stream">The photo stream</param> /// <param name="photoOrientation">The orientation metadata to apply to the photo</param> /// <returns></returns> private static async Task ReencodeAndSavePhotoAsync(IRandomAccessStream stream, PhotoOrientation photoOrientation) { using (var inputStream = stream) { var decoder = await BitmapDecoder.CreateAsync(inputStream); var file = await KnownFolders.PicturesLibrary.CreateFileAsync("SimplePhoto.jpeg", CreationCollisionOption.GenerateUniqueName); using (var outputStream = await file.OpenAsync(FileAccessMode.ReadWrite)) { var encoder = await BitmapEncoder.CreateForTranscodingAsync(outputStream, decoder); var properties = new BitmapPropertySet { { "System.Photo.Orientation", new BitmapTypedValue(photoOrientation, PropertyType.UInt16) } }; await encoder.BitmapProperties.SetPropertiesAsync(properties); await encoder.FlushAsync(); } } }
private async Task <IRandomAccessStream> ResizeStreamAsync(IRandomAccessStream stream, Size size, PhotoOrientation orientation) { var rotation = 0; switch (orientation) { case PhotoOrientation.Rotate180: { rotation = -180; }; break; case PhotoOrientation.Rotate270: { rotation = -270; }; break; case PhotoOrientation.Rotate90: { rotation = -90; }; break; } using (var resizedStream = new InMemoryRandomAccessStream()) { var buffer = new byte[stream.Size].AsBuffer(); stream.Seek(0); await stream.ReadAsync(buffer, buffer.Length, InputStreamOptions.None); var resizeConfiguration = new AutoResizeConfiguration( (uint)(size.Width * size.Height * 4 * 2), size, new Size(0, 0), AutoResizeMode.Automatic, 0.7, ColorSpace.Yuv420); buffer = await JpegTools.AutoResizeAsync(buffer, resizeConfiguration); await resizedStream.WriteAsync(buffer); await resizedStream.FlushAsync(); if (rotation != 0) { resizedStream.Seek(0); var filters = new List <IFilter>() { new RotationFilter(rotation) }; using (var source = new RandomAccessStreamImageSource(resizedStream)) using (var effect = new FilterEffect(source) { Filters = filters }) using (var renderer = new JpegRenderer(effect)) { buffer = await renderer.RenderAsync(); using (var rotatedResizedStream = new InMemoryRandomAccessStream()) { await rotatedResizedStream.WriteAsync(buffer); await rotatedResizedStream.FlushAsync(); return(rotatedResizedStream.CloneStream()); } } } else { return(resizedStream.CloneStream()); } } }