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);
                }
            }
        }
        private async Task loadMeta(Photo photo,
                                    ObservableCollection <Photo> list)
        {
            try {
                if (photo.Disposed)
                {
                    return;
                }
                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);
                var                 img = new BitmapImage();
                Photo.Metadata      metadata;
                DispatcherOperation metaSet;
                try {
                    using (var stream = new UnsafeMemoryMapStream(
                               mmap.CreateViewAccessor(0, 0, MemoryMappedFileAccess.Read),
                               FileAccess.Read)) {
                        var data = stream.Stream;
                        {
                            var decoder = BitmapDecoder.Create(data,
                                                               BitmapCreateOptions.PreservePixelFormat,
                                                               BitmapCacheOption.None);
                            var frames = decoder.Frames;
                            if (frames.Count < 1)
                            {
                                throw new ArgumentException("Image contained no frame data.", nameof(photo));
                            }
                            if (!(frames[0].Metadata is BitmapMetadata imgMeta))
                            {
                                throw new NullReferenceException("Image contained no metadata");
                            }
                            metadata        = Exif.GetMetadata(imgMeta);
                            metadata.Width  = frames[0].PixelWidth;
                            metadata.Height = frames[0].PixelHeight;
                        }

                        data.Seek(0, SeekOrigin.Begin);
                        metaSet = photo.Dispatcher.InvokeAsync(() => photo.Set(metadata));
                        img.BeginInit();
                        img.StreamSource = data;
                        if (3 * metadata.Width > 2 * metadata.Height)
                        {
                            img.DecodePixelWidth = 3 * ThumbnailHeight / 2;
                        }
                        else
                        {
                            img.DecodePixelHeight = ThumbnailHeight;
                        }
                        img.CacheOption = BitmapCacheOption.OnLoad;
                        img.Rotation    = Exif.OrienationToRotation(metadata.Orientation);
                        img.EndInit();
                        img.Freeze();
                    }
                    await metaSet;
                } catch {
                    mmap.Dispose();
                    throw;
                }
                if (!await photo.Dispatcher.InvokeAsync(() => {
                    if (photo.Disposed)
                    {
                        return(false);
                    }
                    photo.mmap = mmap;
                    photo.loader = this;
                    photo.ThumbImage = img;
                    return(true);
                }))
                {
                    mmap.Dispose();
                }
            } 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);
                    photo.Dispose();
                    list.Remove(photo);
                });
            }
        }