public ManagedBitmap CreateTile(ManagedBitmap source, int offsetX, int offsetY, int drawWidth, int drawHeight, int targetWidth, int targetHeight, Profile profile) { EnsureStarted(profile); ManagedBitmap result; string mapId; int width, height; Profile serverProfile; bool succeeded = false; profile.Push("Remote call"); ClientServerCommunication.SendMessage( null /*log*/, channel, ClientServerCommunication.Commands.CreateTileGDI, new object[] { (int)Thread.CurrentThread.Priority, (string)source.BackingName, (int)source.Width, (int)source.Height, (int)offsetX, (int)offsetY, (int)drawWidth, (int)drawHeight, (int)targetWidth, (int)targetHeight }); try { ClientServerCommunication.WaitForPending(channel, out serverProfile, out mapId, out width, out height); profile.Add(serverProfile); result = new ManagedBitmap32(width, height, mapId); succeeded = true; } catch (ClientServerCommunication.RemoteException) { result = ManagedBitmap.CreateFromGDI(new Bitmap(Properties.Resources.InvalidPlaceHolder)); } profile.Pop(); if (succeeded) { profile.Push("Remote call"); ClientServerCommunication.SendMessage( null /*log*/, channel, ClientServerCommunication.Commands.Clear, null); ClientServerCommunication.WaitForDone(channel, out serverProfile); profile.Add(serverProfile); profile.Pop(); } return(result); }
public ManagedBitmap LoadAndOrientGDI(string path, int rightRotations, Profile profile, out RotateFlipType exifOrientation) { EnsureStarted(profile); exifOrientation = RotateFlipType.RotateNoneFlipNone; ManagedBitmap result; string mapId; int width, height; Profile serverProfile; bool succeeded = false; profile.Push("Remote call"); ClientServerCommunication.SendMessage( null /*log*/, channel, ClientServerCommunication.Commands.LoadAndOrientGDI, new object[] { (int)Thread.CurrentThread.Priority, (string)path, (int)rightRotations, }); try { object[] extra = ClientServerCommunication.WaitForPending(channel, out serverProfile, out mapId, out width, out height); exifOrientation = (RotateFlipType)(int)extra[0]; profile.Add(serverProfile); result = new ManagedBitmap32(width, height, mapId); succeeded = true; } catch (ClientServerCommunication.RemoteException) { result = ManagedBitmap.CreateFromGDI(new Bitmap(Properties.Resources.InvalidPlaceHolder)); } profile.Pop(); if (succeeded) { profile.Push("Remote call"); ClientServerCommunication.SendMessage( null /*log*/, channel, ClientServerCommunication.Commands.Clear, null); ClientServerCommunication.WaitForDone(channel, out serverProfile); profile.Add(serverProfile); profile.Pop(); } return(result); }
private static void ResizeGDI(Profile profile, string sourceMapId, int sourceWidth, int sourceHeight, int targetWidth, int targetHeight, out ManagedBitmap targetBitmap) { profile.Push("Resize [GDI]"); using (ManagedBitmap source = new ManagedBitmap32(sourceWidth, sourceHeight, sourceMapId)) { profile.Push("Allocate"); targetBitmap = new ManagedBitmap32(targetWidth, targetHeight); profile.Pop(); Transforms.Resize(profile, source, targetBitmap); } profile.Pop(); }
public ManagedBitmap ShrinkExpandWPF(ManagedBitmap source, double factor, Profile profile) { EnsureStarted(profile); ManagedBitmap result = new ManagedBitmap32(source.Width, source.Height); profile.Push("Remote call"); ClientServerCommunication.SendMessage( null /*log*/, channel, ClientServerCommunication.Commands.ShrinkExpandWPF, new object[] { (int)Thread.CurrentThread.Priority, (int)source.Width, (int)source.Height, (string)source.BackingName, (string)result.BackingName, (double)factor, }); Profile serverProfile; ClientServerCommunication.WaitForDone(channel, out serverProfile); profile.Add(serverProfile); profile.Pop(); return(result); }
public Bitmap AsGDI(Profile profile = null) { bool pop = false; try { if (gdiBitmap != null) { return(gdiBitmap); } if (profile != null) { profile.Push("SmartBitmap.AsGDI"); pop = true; } if (wpfBitmap != null) { Bitmap gdiBitmap = new Bitmap(wpfBitmap.PixelWidth, wpfBitmap.PixelHeight, System.Drawing.Imaging.PixelFormat.Format32bppRgb); ApplyProperties(); BitmapData d = gdiBitmap.LockBits(new Rectangle(0, 0, gdiBitmap.Width, gdiBitmap.Height), ImageLockMode.WriteOnly, ManagedBitmap32.Format); int * scan0 = (int *)d.Scan0.ToPointer(); int stride = d.Stride; Debug.Assert(stride > 0); wpfBitmap.CopyPixels(new System.Windows.Int32Rect(0, 0, gdiBitmap.Width, gdiBitmap.Height), new IntPtr(scan0), stride, 0 /*offset*/); gdiBitmap.UnlockBits(d); wpfBitmap = null; return(gdiBitmap); } if (managedBitmap != null) { gdiBitmap = managedBitmap.CloneToGDI(); managedBitmap.Dispose(); managedBitmap = null; return(gdiBitmap); } } finally { if ((profile != null) && pop) { profile.Pop(); } } Debug.Assert(false); throw new InvalidOperationException(); }
private static void LoadAndOrientGDI(Profile profile, string sourceFilePath, int rightRotations, out ManagedBitmap bitmap, out RotateFlipType exifOrientation) { profile.Push("LoadAndOrient [GDI]"); PropertyItem[] properties; bitmap = Transforms.LoadAndOrientManaged(profile, sourceFilePath, rightRotations, out properties, out exifOrientation); profile.Pop(); }
public ImageServerProxy ObtainProxy(Profile profile) { profile.Push("ObtainProxy"); int which = WaitHandle.WaitAny(proxyGates); ImageServerProxy result = proxies[which]; profile.Pop(); return(result); }
public BitmapFrame AsWPF(Profile profile = null) { bool pop = false; try { if (wpfBitmap != null) { return(wpfBitmap); } if (profile != null) { profile.Push("SmartBitmap.AsWPF"); pop = true; } if (gdiBitmap != null) { BitmapData d = gdiBitmap.LockBits(new Rectangle(0, 0, gdiBitmap.Width, gdiBitmap.Height), ImageLockMode.ReadOnly, ManagedBitmap32.Format); int * scan0 = (int *)d.Scan0.ToPointer(); int stride = d.Stride; Debug.Assert(stride > 0); wpfBitmap = (BitmapFrame)BitmapFrame.Create(gdiBitmap.Width, gdiBitmap.Height, 96, 96, PixelFormats.Bgr32, null, new IntPtr(scan0), gdiBitmap.Width * gdiBitmap.Height * 4, stride); gdiBitmap.UnlockBits(d); gdiBitmap.Dispose(); gdiBitmap = null; return(wpfBitmap); } if (managedBitmap != null) { wpfBitmap = managedBitmap.CloneToWPF(); managedBitmap.Dispose(); managedBitmap = null; return(wpfBitmap); } } finally { if ((profile != null) && pop) { profile.Pop(); } } Debug.Assert(false); throw new InvalidOperationException(); }
private static void ShrinkExpandWPF(Profile profile, int width, int height, string sourceMapName, string targetMapName, double factor) { profile.Push("ShrinkExpand [WPF]"); using (SmartBitmap source = new SmartBitmap(new ManagedBitmap32(width, height, sourceMapName))) { profile.Push("Convert to WPF"); BitmapFrame wpfSource = source.AsWPF(); profile.Pop(); BitmapFrame wpfShrunkExpanded = Transforms.ShrinkExpand(profile, wpfSource, factor); profile.Push("Convert to Managed"); using (ManagedBitmap target = new ManagedBitmap32(wpfShrunkExpanded, targetMapName)) // copy into shared memory { } profile.Pop(); } profile.Pop(); }
private static void ShrinkExpandGDI(Profile profile, int width, int height, string sourceMapName, string targetMapName, double factor) { profile.Push("ShrinkExpand [GDI]"); using (ManagedBitmap source = new ManagedBitmap32(width, height, sourceMapName)) { using (ManagedBitmap target = new ManagedBitmap32(width, height, targetMapName)) { Transforms.ShrinkExpand(profile, source, factor, target); } } profile.Pop(); }
public static ManagedBitmap ShrinkExpandWPF(Profile profile, ManagedBitmap source, double factor) { profile.Push("ImageClient.ShrinkExpandWPF"); ImageServerProxy server = serverPool.ObtainProxy(profile); try { ManagedBitmap result = server.ShrinkExpandWPF(source, factor, profile); return(result); } finally { serverPool.ReleaseProxy(server); profile.Pop(); } }
public static ManagedBitmap CreateTileGDI(Profile profile, ManagedBitmap source, int offsetX, int offsetY, int drawWidth, int drawHeight, int targetWidth, int targetHeight) { profile.Push("ImageClient.CreateTileGDI"); ImageServerProxy server = serverPool.ObtainProxy(profile); try { ManagedBitmap result = server.CreateTile(source, offsetX, offsetY, drawWidth, drawHeight, targetWidth, targetHeight, profile); return(result); } finally { serverPool.ReleaseProxy(server); profile.Pop(); } }
public static ManagedBitmap ResizeGDI(Profile profile, ManagedBitmap source, int targetWidth, int targetHeight) { profile.Push("ImageClient.ResizeGDI"); ImageServerProxy server = serverPool.ObtainProxy(profile); try { ManagedBitmap result = server.ResizeGDI(source, targetWidth, targetHeight, profile); return(result); } finally { serverPool.ReleaseProxy(server); profile.Pop(); } }
public static ManagedBitmap LoadAndOrientGDI(Profile profile, string path, int rightRotations, out RotateFlipType exifOrientation) { profile.Push("ImageClient.LoadAndOrientGDI"); ImageServerProxy server = serverPool.ObtainProxy(profile); try { ManagedBitmap result = server.LoadAndOrientGDI(path, rightRotations, profile, out exifOrientation); return(result); } finally { serverPool.ReleaseProxy(server); profile.Pop(); } }
public ManagedBitmap AsManaged(Profile profile = null) { bool pop = false; try { if (managedBitmap != null) { return(managedBitmap); } if (profile != null) { profile.Push("SmartBitmap.AsManaged"); pop = true; } if (gdiBitmap != null) { managedBitmap = ManagedBitmap.CreateFromGDI(gdiBitmap); gdiBitmap.Dispose(); gdiBitmap = null; return(managedBitmap); } if (wpfBitmap != null) { managedBitmap = new ManagedBitmap32(wpfBitmap); wpfBitmap = null; return(managedBitmap); } } finally { if ((profile != null) && pop) { profile.Pop(); } } Debug.Assert(false); throw new InvalidOperationException(); }
private void EnsureStarted(Profile profile) { if (!started) { profile.Push("EnsureStarted"); string pipeName = Guid.NewGuid().ToString(); // TODO: security - restrict access to child process channel = new NamedPipeServerStream(pipeName); if (!InProc) { remote = new Process(); remote.StartInfo.Arguments = String.Format("-server {0}", pipeName); remote.StartInfo.CreateNoWindow = true; remote.StartInfo.FileName = Assembly.GetExecutingAssembly().Location; remote.StartInfo.UseShellExecute = false; remote.StartInfo.WorkingDirectory = Path.GetTempPath(); remote.Start(); } else { #pragma warning disable CS0162 // unreachable simulatedRemote = new Thread(new ThreadStart( delegate() { ImageServer.RunServer(pipeName); })); simulatedRemote.Name = "ImageServer - InProc"; simulatedRemote.Start(); #pragma warning restore CS0162 } channel.WaitForConnection(); started = true; profile.Pop(); } }
// TODO: untested private unsafe static void CreateTileGDI(Profile profile, string sourceMapId, int sourceWidth, int sourceHeight, int offsetX, int offsetY, int drawWidth, int drawHeight, int targetWidth, int targetHeight, out ManagedBitmap targetBitmap) { profile.Push("CreateTileGDI"); using (ManagedBitmap sourceBitmap = new ManagedBitmap32(sourceWidth, sourceHeight, sourceMapId)) { using (Bitmap sourceBitmapGDI = new Bitmap(sourceWidth, sourceHeight, sourceBitmap.Stride, sourceBitmap.ImageFormat, new IntPtr(sourceBitmap.Scan0))) { targetBitmap = new ManagedBitmap32(targetWidth, targetHeight); using (Bitmap targetBitmapGDI = new Bitmap(targetWidth, targetHeight, targetBitmap.Stride, targetBitmap.ImageFormat, new IntPtr(targetBitmap.Scan0))) { using (Graphics graphics = Graphics.FromImage(targetBitmapGDI)) { graphics.FillRectangle(System.Drawing.Brushes.Black, 0, 0, targetWidth, targetHeight); graphics.DrawImage(sourceBitmapGDI, offsetX, offsetY, drawWidth, drawHeight); } } } } profile.Pop(); }
// use highest quality transforms and no cached bitmaps public static void FinalOutputOne(Item item, Stats stats, Dictionary <string, bool> createdFiles, List <string> messages, CancellationTokenSource cancel) { Profile profile = new Profile("FinalOutput {0}", item.RenamedFileName); profile.Push("Item.WaitInit"); item.WaitInit(); profile.Pop(); DateTime originalCreationTime = File.GetCreationTime(item.SourcePath); DateTime originalLastWriteTime = File.GetLastWriteTime(item.SourcePath); string renamedTargetPath = Path.Combine(Path.GetDirectoryName(item.TargetPath), item.RenamedFileName); if (item.Delete) { // actual deletion occurs after end of run, by file being omitted from createdFiles Interlocked.Increment(ref stats.deleted); } else if (item.Valid) { // load source string tempFile = Path.GetTempFileName(); File.Copy(item.SourcePath, tempFile, true /*overwrite*/); SmartBitmap bitmap = null; bool jpegTranRotationRequired = true; // initial lossy transforms if (item.NormalizeGeometry || (item.FineRotateDegrees != 0)) { if (bitmap == null) { bitmap = new SmartBitmap(Transforms.LoadAndOrientGDI(tempFile, profile)); } jpegTranRotationRequired = false; if (item.RightRotations != 0) { ManagedBitmap bitmap2 = bitmap.AsManaged().RotateFlip(Transforms.RotateFlipFromRightRotations(item.RightRotations)); bitmap.Dispose(); bitmap = new SmartBitmap(bitmap2); } Transforms.ApplyNormalizeGeometry( profile, item.SourceFileName, bitmap.AsManaged(), 1, new Transforms.NormalizeGeometryParameters( item.CornerTL, item.CornerTR, item.CornerBL, item.CornerBR, item.NormalizeGeometryForcedAspectRatio, item.FineRotateDegrees, item.NormalizeGeometryFinalInterp), delegate(string text) { }, cancel); } // lossless transform phase if (bitmap == null) { List <string> jpegtranMessages = new List <string>(); string error; bool rotateOK = true; if (jpegTranRotationRequired && ((item.RightRotations != 0) || (item.OriginalExifOrientation != RotateFlipType.RotateNoneFlipNone))) { rotateOK = false; int combinedRotations = (item.RightRotations + Transforms.RightRotationsFromRotateFlipType(item.OriginalExifOrientation)) % 4; // TODO: strip only Exif orientation after doing this - how? (currently strips all) if (Transforms.LosslessRotateRightFinal( tempFile, tempFile, combinedRotations, out error)) { Interlocked.Increment(ref stats.rotated); rotateOK = true; } else { jpegtranMessages.Add(String.Format("Lossless rotate failed for \"{0}\" ({1}).", item.RenamedFileName, error)); } } bool cropOK = true; if (!item.CropRect.IsEmpty) { cropOK = false; if (Transforms.LosslessCropFinal(tempFile, tempFile, item.CropRect, out error)) { Interlocked.Increment(ref stats.cropped); cropOK = true; } else { jpegtranMessages.Add(String.Format("Lossless crop failed for \"{0}\" ({1}).", item.RenamedFileName, error)); } } if (!rotateOK || !cropOK) { // If jpegtran is unable to handle image (e.g. dimensions not integral multiples - as generated by // some cameras), fall back to lossy rotation and log a message. bitmap = new SmartBitmap(Transforms.LoadAndOrientGDI(tempFile, profile)); if (!rotateOK) { ManagedBitmap bitmap2 = bitmap.AsManaged().RotateFlip(Transforms.RotateFlipFromRightRotations(item.RightRotations)); bitmap.Dispose(); bitmap = new SmartBitmap(bitmap2); } if (!cropOK) { ManagedBitmap bitmap2 = bitmap.AsManaged().Crop(item.CropRect); bitmap.Dispose(); bitmap = new SmartBitmap(bitmap2); } jpegtranMessages.Add("Using lossy rotation/crop instead."); lock (messages) { messages.Add(String.Join(" ", jpegtranMessages.ToArray())); } } } else { // whoops- preceding transform prevents jpegtran from being used (recreating jpeg would be lossy) if (!item.CropRect.IsEmpty) { ManagedBitmap bitmap2 = bitmap.AsManaged().Crop(item.CropRect); bitmap.Dispose(); bitmap = new SmartBitmap(bitmap2); } } // following lossy transforms phase if (item.Unbias) { if (bitmap == null) { bitmap = new SmartBitmap(Transforms.LoadAndOrientGDI(tempFile, profile)); } Transforms.PolyUnbiasDiagnostics unused; Transforms.ApplyPolyUnbias( profile, item.RenamedFileName, bitmap.AsManaged(profile), Rectangle.Empty /*already cropped*/, new Transforms.PolyUnbiasParameters( item.UnbiasMaxDegree, item.UnbiasMaxChisq, item.UnbiasMaxS, item.UnbiasMinV), null, out unused, cancel); Interlocked.Increment(ref stats.polyUnbias); } if (item.BrightAdjust) { if (bitmap == null) { bitmap = new SmartBitmap(Transforms.LoadAndOrientGDI(tempFile, profile)); } Transforms.ApplyBrightAdjust( profile, item.RenamedFileName, bitmap.AsManaged(profile), Rectangle.Empty /*already cropped*/, new Transforms.BrightAdjustParameters(item.BrightAdjustMinClusterFrac, item.BrightAdjustWhiteCorrect), null, cancel); Interlocked.Increment(ref stats.brightAdjust); } if (item.StaticSaturate) { if (bitmap == null) { bitmap = new SmartBitmap(Transforms.LoadAndOrientGDI(tempFile, profile)); } Transforms.ApplyStaticSaturation( profile, item.RenamedFileName, bitmap.AsManaged(profile), Rectangle.Empty /*already cropped*/, new Transforms.StaticSaturateParameters(item.StaticSaturateWhiteThreshhold, item.StaticSaturateBlackThreshhold, item.StaticSaturateExponent), cancel); } if (item.Shrink) { if (bitmap == null) { bitmap = new SmartBitmap(Transforms.LoadAndOrientGDI(tempFile, profile)); } //Bitmap shrunk = Transforms.Shrink(profile, bitmap.AsGDI(profile), item.ShrinkFactor); int newWidth = (int)Math.Floor(bitmap.Width / item.ShrinkFactor); int newHeight = (int)Math.Floor(bitmap.Height / item.ShrinkFactor); ManagedBitmap bitmap2 = ImageClient.ResizeGDI(profile, bitmap.AsManaged(profile), newWidth, newHeight); bitmap.Dispose(); bitmap = new SmartBitmap(bitmap2); Interlocked.Increment(ref stats.shrunk); } // TODO: eliminate shrink and OneBit's expand if both are configured if (item.OneBit) { if (bitmap == null) { bitmap = new SmartBitmap(Transforms.LoadAndOrientGDI(tempFile, profile)); } SmartBitmap bitmap2 = new SmartBitmap( Transforms.ApplyOneBit( profile, item.RenamedFileName, bitmap, new Transforms.OneBitParameters(item.OneBitChannel, item.OneBitThreshhold, item.OneBitScaleUp), cancel)); bitmap.Dispose(); bitmap = bitmap2; Interlocked.Increment(ref stats.oneBit); } if (bitmap != null) { Transforms.SaveImage(profile, bitmap, tempFile, item.JpegQuality, item.JpegUseGdi, item.OutputFormat); bitmap.Dispose(); } // write target string targetPath; bool extUpper = String.Equals(Path.GetExtension(renamedTargetPath), Path.GetExtension(renamedTargetPath).ToUpper()); switch (item.OutputFormat) { default: Debug.Assert(false); throw new ArgumentException(); case OutputFormat.Jpeg: targetPath = Path.ChangeExtension(renamedTargetPath, extUpper ? ".JPG" : ".jpg"); break; case OutputFormat.Bmp: targetPath = Path.ChangeExtension(renamedTargetPath, extUpper ? ".BMP" : ".bmp"); break; case OutputFormat.Png: targetPath = Path.ChangeExtension(renamedTargetPath, extUpper ? ".PNG" : ".png"); break; } for (int i = 0; i <= RetryCount; i++) { try { File.Copy(tempFile, targetPath, true /*overwrite*/); File.SetCreationTime(targetPath, originalCreationTime); File.SetLastWriteTime(targetPath, DateTime.Now); } catch (IOException) when(i < RetryCount) { // HACK: If folder is open, Explorer may have file locked to refresh thumbnail Thread.Sleep(SleepRetry); } } lock (createdFiles) { createdFiles.Add(Path.GetFileName(targetPath).ToLowerInvariant(), false); } File.Delete(tempFile); } else { lock (createdFiles) { createdFiles.Add(Path.GetFileName(renamedTargetPath).ToLowerInvariant(), false); } if (!String.Equals(item.SourcePath, renamedTargetPath, StringComparison.OrdinalIgnoreCase)) { File.Copy(item.SourcePath, renamedTargetPath, true /*overwrite*/); } } profile.End(); Program.Log(LogCat.Perf, profile.Report()); }
public void StartSwapOut(ImageCache cache) { lock (this) { Debug.Assert(Program.EnableSwap); if (this.outTask != null) { return; } if (this.holders.Count != 0) { return; } Stopwatch elapsed = Stopwatch.StartNew(); #if true // TODO: remove hack EventWaitHandle swapOutDelay = new EventWaitHandle(false, EventResetMode.AutoReset); #endif Task <bool> serializationTask = null; Task <ManagedBitmap> oldBitmap = this.bitmap; // 'this' is not locked at the time 'cache' is used below in the task delegates this.outTask = new Task <bool>( delegate() { Profile profile = new Profile("SwapOut {0}", this.id); #if true // TODO: remove hack profile.Push("Hack delay for swapins"); // HACK: wait a little to allow swapins to start before swapouts EventWaitHandle localSwapOutDelay = Interlocked.Exchange(ref swapOutDelay, null); if (localSwapOutDelay != null) // race: swapin can grab and clear this before we get here { localSwapOutDelay.WaitOne(100); } profile.Pop(); // #endif profile.Push("WaitSwapOutGate"); cache.WaitSwapOutGate(); // defer to in-flight swapins profile.Pop(); lock (this) { Debug.Assert(this.swapFilePath == null); Debug.Assert(this.swapFileStream == null); this.swapFilePath = Path.GetTempFileName(); this.swapFileStream = new FileStream(this.swapFilePath, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite, 4096, FileOptions.DeleteOnClose); } profile.Push("oldBitmap.Wait()"); oldBitmap.Wait(); // wait for an old in-flight creation to complete profile.Pop(); profile.Push("Serialize"); serializationTask = new Task <bool>( delegate() { SetIOPriority(this.swapFileStream, PRIORITY_HINT.IoPriorityHintLow); ManagedBitmap.Serialize(this.swapFileStream, oldBitmap.Result); SetIOPriority(this.swapFileStream, PRIORITY_HINT.IoPriorityHintNormal); return(false); }); SerializationManager.Manager.EnqueueWriteTask(serializationTask); serializationTask.Wait(); profile.Pop(); profile.Push("Enqueue oldBitmap"); lock (this) { this.oldBitmaps.Add(oldBitmap.Result); // remove current bitmap and enqueue for destruction upon zero refs } profile.Pop(); profile.Push("Epilog"); cache.Trace("swapout", this, elapsed); cache.PurgeDisposeList(); profile.Pop(); profile.End(); //Program.Log(LogCat.Perf, profile.ToString()); return(false); }); this.bitmap = new Task <ManagedBitmap>( delegate() { Profile profile = new Profile("SwapIn {0}", this.id); profile.Push("outTask.Wait()"); #if true // TODO: remove hack // HACK: release delay immediately if swapin is requested EventWaitHandle localSwapOutDelay = Interlocked.Exchange(ref swapOutDelay, null); if (localSwapOutDelay != null) { localSwapOutDelay.Set(); } // #endif SerializationManager.Manager.Prioritize(serializationTask); Debug.Assert(this.outTask != null); this.outTask.Wait(); // ensure in-progress swapout finishes profile.Pop(); profile.Push("cache.BeginSwapIn()"); cache.BeginSwapIn(); profile.Pop(); try { Stopwatch elapsed2 = Stopwatch.StartNew(); Debug.Assert(this.swapFilePath != null); Debug.Assert(this.swapFileStream != null); profile.Push("Deserialize"); ManagedBitmap bitmap = null; Task <bool> deserializationTask = new Task <bool>( delegate() { bitmap = ManagedBitmap.Deserialize(this.swapFileStream); return(false); }); SerializationManager.Manager.EnqueueReadTask(deserializationTask); deserializationTask.Wait(); this.swapFilePath = null; Stream localSwapFileStream = this.swapFileStream; this.swapFileStream = null; localSwapFileStream.Dispose(); this.outTask = null; profile.Pop(); profile.Push("Epilog"); cache.Trace("swapin", this, elapsed2); cache.PurgeDisposeList(); StartBitmapCompleteWaiter(); return(bitmap); } finally { cache.EndSwapIn(); #if true // TODO: remove hack if (localSwapOutDelay != null) { localSwapOutDelay.Dispose(); } #endif profile.Pop(); // Epilog - here to include cache.EndSwapIn() profile.End(); //Program.Log(LogCat.Perf, profile.ToString()); } }); this.outTask.Start(); } }