private static void makeFullImage(Photo.Metadata metadata, BitmapImage img) { if (DownsampleFullImage && ( metadata.Width > SystemParameters.MaximizedPrimaryScreenWidth || metadata.Height > SystemParameters.MaximizedPrimaryScreenHeight)) { if (metadata.Width * SystemParameters.MaximizedPrimaryScreenHeight > metadata.Height * SystemParameters.MaximizedPrimaryScreenWidth) { img.DecodePixelWidth = (int)SystemParameters.MaximizedPrimaryScreenWidth; } else { img.DecodePixelHeight = (int)SystemParameters.MaximizedPrimaryScreenHeight; } } img.CacheOption = BitmapCacheOption.None; img.Rotation = Exif.OrienationToRotation(metadata.Orientation); img.EndInit(); img.Freeze(); }
private static async Task <Photo.Metadata> reloadAndSave( Photo photo, bool forceJpeg, string destFile) { using (var mmap = MemoryMappedFile.OpenExisting( mmapName(photo.FileName), MemoryMappedFileRights.Read)) { using (var stream = new UnsafeMemoryMapStream( mmap.CreateViewAccessor(0, 0, MemoryMappedFileAccess.Read), FileAccess.Read)) { (var sourceFrame, var format) = loadFrame(stream.Stream); var md = sourceFrame.Metadata.Clone() as BitmapMetadata; Photo.Metadata newMetadata = await Exif.SetMetadata(photo, md); newMetadata.Width = sourceFrame.PixelWidth; newMetadata.Height = sourceFrame.PixelHeight; BitmapEncoder encoder = forceJpeg ? new JpegBitmapEncoder() : BitmapEncoder.Create(format); encoder.Frames.Add( BitmapFrame.Create( sourceFrame, null, md, sourceFrame.ColorContexts)); if (encoder is JpegBitmapEncoder jpg) { jpg.Rotation = Exif.SaveRotation(md); } sourceFrame = null; using (var outFile = new FileStream(destFile, FileMode.CreateNew)) { encoder.Save(outFile); } return(newMetadata); } } }
/// <summary> /// Remove <paramref name="oldFile"/> after closing any handles /// <paramref name="photo"/> might have open for it and replacing them /// with new ones. /// </summary> private static async Task reloadAndRemove(Photo photo, Photo.Metadata metadata, string oldFile) { var oldMmap = await photo.Dispatcher.InvokeAsync(() => { if (photo.Disposed) { return(mmap : null, stream : null); } return(mmap : Interlocked.Exchange(ref photo.mmap, null), stream : Interlocked.Exchange(ref photo.fullImageStream, null)); }); if (oldMmap.mmap != null) { try { if (oldMmap.stream != null) { oldMmap.stream.Dispose(); } } finally { oldMmap.mmap.Dispose(); } try { var mmap = MemoryMappedFile.CreateFromFile( File.Open(photo.FileName, FileMode.Open, FileAccess.Read, FileShare.Delete | FileShare.Read), mmapName(photo.FileName), 0, MemoryMappedFileAccess.Read, HandleInheritability.None, false); if (await photo.Dispatcher.InvokeAsync(() => { if (photo.Disposed) { return(false); } photo.mmap = mmap; return(true); })) { await setImage(photo, metadata, false); } else { mmap.Dispose(); } } catch (Exception ex) { await photo.Dispatcher.InvokeAsync(() => { MessageBox.Show(ex.ToString(), string.Format("Reloading {0}\n\n{1}", photo.FileName, ex), MessageBoxButton.OK, MessageBoxImage.Error); }); } } try { File.Delete(oldFile); } catch (Exception ex) { await photo.Dispatcher.InvokeAsync(() => { MessageBox.Show(ex.ToString(), string.Format("Error overwriting {0}\n\n{1}", photo.FileName, ex), MessageBoxButton.OK, MessageBoxImage.Error); }); } }
internal void EnqueueFullSizeRead(Photo photo, Photo.Metadata meta) { fullsizeReads.Add(new Tuple <Photo, Photo.Metadata>(photo, meta)); makeIOThread(); }
private async static Task setImage(Photo photo, Photo.Metadata metadata, bool mustLock) { bool locked = false; if (photo.Disposed) { return; } try { if (mustLock) { // To avoid dispose colliding with setImage. await photo.loadLock.WaitAsync(); locked = true; } if (photo.Disposed) { return; } var(mmap, fullImageStream) = await photo.Dispatcher.InvokeAsync( () => (photo.mmap, photo.fullImageStream)); if (mmap == null) { // disposed return; } if (fullImageStream == null) { fullImageStream = new UnsafeMemoryMapStream( mmap.CreateViewAccessor(0, 0, MemoryMappedFileAccess.Read), FileAccess.Read); await photo.Dispatcher.InvokeAsync(() => { var p = Interlocked.CompareExchange( ref photo.fullImageStream, fullImageStream, null); if (p != null) { fullImageStream.Dispose(); fullImageStream = p; } }); } var img = new BitmapImage(); try { img.BeginInit(); img.StreamSource = fullImageStream.Stream; makeFullImage(metadata, img); } catch (Exception ex) { await photo.Dispatcher.InvokeAsync(() => { MessageBox.Show(ex.ToString(), string.Format("Error loading {0}\n\n{1}", photo.FileName, ex), MessageBoxButton.OK, MessageBoxImage.Error); }); return; } await photo.Dispatcher.InvokeAsync(() => { photo.FullImage = img; }); } finally { if (locked) { photo.loadLock.Release(); } } // Now is a good time to do a gen-0 GC to make sure the image we // just loaded gets promoted to at least gen1 before its caching // expires. GC.Collect(0); }