-
Notifications
You must be signed in to change notification settings - Fork 5.4k
Implement CachedBitmap #39245
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Implement CachedBitmap #39245
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
22 changes: 22 additions & 0 deletions
22
src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/CachedBitmap.Unix.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
|
|
||
| using System.Diagnostics.CodeAnalysis; | ||
| using Gdip = System.Drawing.SafeNativeMethods.Gdip; | ||
|
|
||
| namespace System.Drawing.Imaging | ||
| { | ||
| public sealed partial class CachedBitmap | ||
| { | ||
| internal static bool IsCachedBitmapSupported() | ||
| { | ||
| // CachedBitmap is only supported on libgdiplus 6.1 and above. | ||
| // The function to check for the version is only present on libgdiplus 6.0 and above. | ||
| if (Gdip.GetLibgdiplusVersion is null) | ||
| return false; | ||
|
|
||
| var version = new Version(Gdip.GetLibgdiplusVersion()); | ||
| return version.Major > 6 || version.Major == 6 && version.Minor >= 1; | ||
| } | ||
| } | ||
| } | ||
10 changes: 10 additions & 0 deletions
10
src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/CachedBitmap.Windows.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
|
|
||
| namespace System.Drawing.Imaging | ||
| { | ||
| public sealed partial class CachedBitmap | ||
| { | ||
| internal static bool IsCachedBitmapSupported() => true; | ||
| } | ||
| } |
61 changes: 61 additions & 0 deletions
61
src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/CachedBitmap.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
|
|
||
| using System.Runtime.InteropServices; | ||
| using Gdip = System.Drawing.SafeNativeMethods.Gdip; | ||
|
|
||
| namespace System.Drawing.Imaging | ||
| { | ||
| /// <summary> | ||
| /// Stores a <see cref="Bitmap"/> in a format that is optimized for display on a particular device. | ||
| /// </summary> | ||
| public sealed partial class CachedBitmap : IDisposable | ||
| { | ||
| internal static readonly bool IsSupported = IsCachedBitmapSupported(); | ||
| internal IntPtr nativeCachedBitmap; | ||
|
reflectronic marked this conversation as resolved.
Outdated
|
||
|
|
||
| /// <summary> | ||
| /// Initializes a new instance of the <see cref="CachedBitmap"/> class. | ||
| /// </summary> | ||
| /// <param name="bitmap">The bitmap to take the pixel data from.</param> | ||
| /// <param name="graphics">A <see cref="Graphics"/> object, representing the display device to optimize the bitmap for.</param> | ||
| /// <exception cref="ArgumentNullException"> | ||
| /// <paramref name="bitmap"/> is <see langword="null" />. | ||
| /// - or - | ||
| /// <paramref name="graphics"/> is <see langword="null" /> | ||
| /// </exception> | ||
| /// <exception cref="PlatformNotSupportedException"> | ||
| /// The installed version of libgdiplus is lower than 6.1. This does not apply on Windows. | ||
| /// </exception> | ||
| public CachedBitmap(Bitmap bitmap, Graphics graphics) | ||
| { | ||
| if (bitmap is null) | ||
| throw new ArgumentNullException(nameof(bitmap)); | ||
|
|
||
| if (graphics is null) | ||
| throw new ArgumentNullException(nameof(graphics)); | ||
|
|
||
| if (!IsSupported) | ||
| throw new PlatformNotSupportedException(SR.CachedBitmapNotSupported); | ||
|
|
||
| int status = Gdip.GdipCreateCachedBitmap(new HandleRef(bitmap, bitmap.nativeImage), | ||
| new HandleRef(graphics, graphics.NativeGraphics), | ||
| out nativeCachedBitmap); | ||
|
|
||
| Gdip.CheckStatus(status); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Releases all resources used by this <see cref="CachedBitmap"/>. | ||
| /// </summary> | ||
| public void Dispose() | ||
| { | ||
| if (nativeCachedBitmap != IntPtr.Zero) | ||
| { | ||
| int status = Gdip.GdipDeleteCachedBitmap(new HandleRef(this, nativeCachedBitmap)); | ||
| nativeCachedBitmap = IntPtr.Zero; | ||
| Gdip.CheckStatus(status); | ||
| } | ||
| } | ||
| } | ||
| } | ||
137 changes: 137 additions & 0 deletions
137
src/libraries/System.Drawing.Common/tests/Imaging/CachedBitmapTests.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,137 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
|
|
||
| using System; | ||
| using System.Collections; | ||
| using System.Collections.Generic; | ||
| using System.Drawing.Imaging; | ||
| using System.Linq; | ||
| using System.Security.Permissions; | ||
| using System.Text; | ||
| using System.Threading.Tasks; | ||
|
|
||
| using Xunit; | ||
|
|
||
| namespace System.Drawing.Imaging.Tests | ||
| { | ||
| public class CachedBitmapTests | ||
| { | ||
| [ConditionalFact(Helpers.IsCachedBitmapSupported)] | ||
| public void Ctor_Throws_ArgumentNullException() | ||
| { | ||
| using var bitmap = new Bitmap(10, 10); | ||
| using var graphics = Graphics.FromImage(bitmap); | ||
|
|
||
| Assert.Throws<ArgumentNullException>(() => new CachedBitmap(bitmap, null)); | ||
| Assert.Throws<ArgumentNullException>(() => new CachedBitmap(null, graphics)); | ||
| } | ||
|
|
||
| [ConditionalFact(Helpers.IsCachedBitmapSupported)] | ||
| public void Disposed_CachedBitmap_Throws_ArgumentException() | ||
| { | ||
| using var bitmap = new Bitmap(10, 10); | ||
| using var graphics = Graphics.FromImage(bitmap); | ||
| using var cached = new CachedBitmap(bitmap, graphics); | ||
|
|
||
| cached.Dispose(); | ||
|
|
||
| Assert.Throws<ArgumentException>(() => graphics.DrawCachedBitmap(cached, 0, 0)); | ||
| } | ||
|
|
||
| [ConditionalFact(Helpers.IsCachedBitmapSupported)] | ||
| public void DrawCachedBitmap_Throws_ArgumentNullException() | ||
| { | ||
| using var bitmap = new Bitmap(10, 10); | ||
| using var graphics = Graphics.FromImage(bitmap); | ||
| Assert.Throws<ArgumentNullException>(() => graphics.DrawCachedBitmap(null, 0, 0)); | ||
| } | ||
|
|
||
| static string[] bitmaps = new string[] | ||
| { | ||
| "81674-2bpp.png", | ||
| "64x64_one_entry_8bit.ico", | ||
| "16x16_one_entry_4bit.ico", | ||
| "16x16_nonindexed_24bit.png" | ||
| }; | ||
|
|
||
| public class CachedBitmapOffsetTestData : IEnumerable<object[]> | ||
| { | ||
| public IEnumerator<object[]> GetEnumerator() | ||
| { | ||
| foreach (string bitmap in bitmaps) | ||
| { | ||
| yield return new object[] { bitmap, 0, 0 }; | ||
| yield return new object[] { bitmap, 20, 20 }; | ||
| yield return new object[] { bitmap, 200, 200 }; | ||
| } | ||
| } | ||
|
|
||
| IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); | ||
| } | ||
|
|
||
| static void CompareEqual(Bitmap expected, Bitmap actual, int xOffset = 0, int yOffset = 0) | ||
| { | ||
| for (int x = 0; x < expected.Width; x++) | ||
| { | ||
| for (int y = 0; y < expected.Height; y++) | ||
| { | ||
| Color expectedColor = expected.GetPixel(x, y); | ||
| Color actualColor = actual.GetPixel(x + xOffset, y + yOffset); | ||
| Assert.Equal(expectedColor, actualColor); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| [ConditionalTheory(Helpers.IsCachedBitmapSupported)] | ||
| [ClassData(typeof(CachedBitmapOffsetTestData))] | ||
| public void CachedBitmap_Drawing_Roundtrips(string filename, int xOffset, int yOffset) | ||
| { | ||
| using var originalBitmap = new Bitmap(Helpers.GetTestBitmapPath(filename)); | ||
|
|
||
| using var surface = new Bitmap(originalBitmap.Width + xOffset, originalBitmap.Height + yOffset); | ||
| using var graphics = Graphics.FromImage(surface); | ||
| using var cachedBitmap = new CachedBitmap(originalBitmap, graphics); | ||
|
|
||
| graphics.DrawCachedBitmap(cachedBitmap, xOffset, yOffset); | ||
|
|
||
| CompareEqual(originalBitmap, surface, xOffset, yOffset); | ||
| } | ||
|
|
||
| [ConditionalFact(Helpers.IsCachedBitmapSupported)] | ||
| public void CachedBitmap_Respects_ClipRectangle() | ||
| { | ||
| using var originalBitmap = new Bitmap(Helpers.GetTestBitmapPath("cachedbitmap_test_original.png")); | ||
| using var clippedBitmap = new Bitmap(Helpers.GetTestBitmapPath("cachedbitmap_test_clip_20_20_20_20.png")); | ||
|
|
||
| using var surface = new Bitmap(originalBitmap.Width, originalBitmap.Height); | ||
| using var graphics = Graphics.FromImage(surface); | ||
| using var cachedBitmap = new CachedBitmap(originalBitmap, graphics); | ||
|
|
||
| graphics.Clip = new Region(new Rectangle(20, 20, 20, 20)); | ||
| graphics.DrawCachedBitmap(cachedBitmap, 0, 0); | ||
|
|
||
| CompareEqual(clippedBitmap, surface); | ||
| } | ||
|
|
||
| [ConditionalFact(Helpers.IsCachedBitmapSupported)] | ||
| public void CachedBitmap_Respects_TranslationMatrix() | ||
| { | ||
| using var originalBitmap = new Bitmap(Helpers.GetTestBitmapPath("cachedbitmap_test_original.png")); | ||
| using var translatedBitmap = new Bitmap(Helpers.GetTestBitmapPath("cachedbitmap_test_translate_30_30.png")); | ||
|
|
||
| using var surface = new Bitmap(originalBitmap.Width, originalBitmap.Height); | ||
| using var graphics = Graphics.FromImage(surface); | ||
| using var cachedBitmap = new CachedBitmap(originalBitmap, graphics); | ||
|
|
||
| graphics.TranslateTransform(30, 30); | ||
| graphics.DrawCachedBitmap(cachedBitmap, 0, 0); | ||
|
|
||
| CompareEqual(translatedBitmap, surface); | ||
|
|
||
| graphics.ScaleTransform(30, 30); | ||
| Assert.Throws<InvalidOperationException>(() => graphics.DrawCachedBitmap(cachedBitmap, 0, 0)); | ||
| graphics.RotateTransform(30); | ||
| Assert.Throws<InvalidOperationException>(() => graphics.DrawCachedBitmap(cachedBitmap, 0, 0)); | ||
| } | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.