Skip to content

Commit 87a03db

Browse files
committed
feat: Xplat support for image loading and saving from memory
1 parent 0e280e0 commit 87a03db

File tree

3 files changed

+30
-19
lines changed

3 files changed

+30
-19
lines changed

sources/engine/Stride/Graphics/StandardImageHelper.Windows.cs renamed to sources/engine/Stride/Graphics/StandardImageHelper.Desktop.cs

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,26 +7,25 @@
77
using System.IO;
88
using System.Runtime.CompilerServices;
99
using System.Runtime.InteropServices;
10+
using FreeImageAPI;
1011
using Stride.Core;
1112

1213
namespace Stride.Graphics
1314
{
1415
/// <summary>
1516
/// This class is responsible to provide image loader for png, gif, bmp.
16-
/// TODO: Replace using System.Drawing, as it is not available on all platforms (not on Windows 8/WP8).
1717
/// </summary>
1818
partial class StandardImageHelper
1919
{
2020
public static unsafe Image LoadFromMemory(IntPtr pSource, int size, bool makeACopy, GCHandle? handle)
2121
{
2222
using var memoryStream = new UnmanagedMemoryStream((byte*)pSource, size, capacity: size, access: FileAccess.Read);
23-
using var bitmap = (Bitmap)System.Drawing.Image.FromStream(memoryStream);
23+
using var bitmap = FreeImageBitmap.FromStream(memoryStream);
2424
var sourceArea = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
25-
// Lock System.Drawing.Bitmap
25+
//Temp copy of FreeImageBitmap
2626

27-
var bitmapData = bitmap.LockBits(sourceArea, ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
27+
var bitmapData = bitmap.Copy(sourceArea).ConvertTo32Bits();
2828
var image = Image.New2D(bitmap.Width, bitmap.Height, 1, PixelFormat.B8G8R8A8_UNorm, 1, bitmapData.Stride);
29-
// var dataRect = new DataRectangle(bitmapData.Stride, bitmapData.Scan0);
3029

3130
try
3231
{
@@ -38,7 +37,8 @@ public static unsafe Image LoadFromMemory(IntPtr pSource, int size, bool makeACo
3837
}
3938
finally
4039
{
41-
bitmap.UnlockBits(bitmapData);
40+
bitmap.Paste(bitmapData, new (sourceArea.X, sourceArea.Y), 255);
41+
bitmapData.Dispose();
4242

4343
if (handle != null)
4444
handle.Value.Free();
@@ -51,55 +51,55 @@ public static unsafe Image LoadFromMemory(IntPtr pSource, int size, bool makeACo
5151

5252
public static void SaveGifFromMemory(PixelBuffer[] pixelBuffers, int count, ImageDescription description, Stream imageStream)
5353
{
54-
SaveFromMemory(pixelBuffers, count, description, imageStream, ImageFormat.Gif);
54+
SaveFromMemory(pixelBuffers, count, description, imageStream, FREE_IMAGE_FORMAT.FIF_GIF);
5555
}
5656

5757
public static void SaveTiffFromMemory(PixelBuffer[] pixelBuffers, int count, ImageDescription description, Stream imageStream)
5858
{
59-
SaveFromMemory(pixelBuffers, count, description, imageStream, ImageFormat.Tiff);
59+
SaveFromMemory(pixelBuffers, count, description, imageStream, FREE_IMAGE_FORMAT.FIF_TIFF);
6060
}
6161

6262
public static void SaveBmpFromMemory(PixelBuffer[] pixelBuffers, int count, ImageDescription description, Stream imageStream)
6363
{
64-
SaveFromMemory(pixelBuffers, count, description, imageStream, ImageFormat.Bmp);
64+
SaveFromMemory(pixelBuffers, count, description, imageStream, FREE_IMAGE_FORMAT.FIF_BMP);
6565
}
6666

6767
public static void SaveJpgFromMemory(PixelBuffer[] pixelBuffers, int count, ImageDescription description, Stream imageStream)
6868
{
69-
SaveFromMemory(pixelBuffers, count, description, imageStream, ImageFormat.Jpeg);
69+
SaveFromMemory(pixelBuffers, count, description, imageStream, FREE_IMAGE_FORMAT.FIF_BMP);
7070
}
7171

7272
public static void SavePngFromMemory(PixelBuffer[] pixelBuffers, int count, ImageDescription description, Stream imageStream)
7373
{
74-
SaveFromMemory(pixelBuffers, count, description, imageStream, ImageFormat.Png);
74+
SaveFromMemory(pixelBuffers, count, description, imageStream, FREE_IMAGE_FORMAT.FIF_PNG);
7575
}
7676

7777
public static void SaveWmpFromMemory(PixelBuffer[] pixelBuffers, int count, ImageDescription description, Stream imageStream)
7878
{
7979
throw new NotImplementedException();
8080
}
8181

82-
private static unsafe void SaveFromMemory(PixelBuffer[] pixelBuffers, int count, ImageDescription description, Stream imageStream, ImageFormat imageFormat)
82+
private static unsafe void SaveFromMemory(PixelBuffer[] pixelBuffers, int count, ImageDescription description, Stream imageStream, FREE_IMAGE_FORMAT imageFormat)
8383
{
84-
using var bitmap = new Bitmap(description.Width, description.Height);
84+
using var bitmap = new FreeImageBitmap(description.Width, description.Height);
8585
var sourceArea = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
8686

87-
// Lock System.Drawing.Bitmap
88-
var bitmapData = bitmap.LockBits(sourceArea, ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
87+
//Temp copy of FreeImageBitmap
88+
var bitmapData = bitmap.Copy(sourceArea).ConvertTo32Bits();
8989

9090
try
9191
{
9292
// Copy memory
9393
var format = description.Format;
94-
if (format == PixelFormat.R8G8B8A8_UNorm || format == PixelFormat.R8G8B8A8_UNorm_SRgb)
94+
if (format is PixelFormat.R8G8B8A8_UNorm or PixelFormat.R8G8B8A8_UNorm_SRgb)
9595
{
9696
CopyMemoryBGRA(bitmapData.Scan0, pixelBuffers[0].DataPointer, pixelBuffers[0].BufferStride);
9797
}
98-
else if (format == PixelFormat.B8G8R8A8_UNorm || format == PixelFormat.B8G8R8A8_UNorm_SRgb)
98+
else if (format is PixelFormat.B8G8R8A8_UNorm or PixelFormat.B8G8R8A8_UNorm_SRgb)
9999
{
100100
Unsafe.CopyBlockUnaligned((void*)bitmapData.Scan0, (void*)pixelBuffers[0].DataPointer, (uint)pixelBuffers[0].BufferStride);
101101
}
102-
else if (format == PixelFormat.R8_UNorm || format == PixelFormat.A8_UNorm)
102+
else if (format is PixelFormat.R8_UNorm or PixelFormat.A8_UNorm)
103103
{
104104
// TODO Ideally we will want to support grayscale images, but the SpriteBatch can only render RGBA for now
105105
// so convert the grayscale image as an RGBA and save it
@@ -114,7 +114,8 @@ private static unsafe void SaveFromMemory(PixelBuffer[] pixelBuffers, int count,
114114
}
115115
finally
116116
{
117-
bitmap.UnlockBits(bitmapData);
117+
bitmap.Paste(bitmapData, new (sourceArea.X, sourceArea.Y), 255);
118+
bitmapData.Dispose();
118119
}
119120

120121
// Save

sources/engine/Stride/Stride.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
<!-- SharpDX is needed for WIC -->
3333
<PackageReference Include="SharpDX.Direct2D1" Condition="'$(TargetFramework)' == '$(StrideFrameworkUWP)'" />
3434
<PackageReference Include="System.Drawing.Common" Condition="'$(TargetFramework)' == '$(StrideFramework)'" />
35+
<ProjectReference Include="..\..\tools\Stride.FreeImage\Stride.FreeImage.csproj" />
3536
</ItemGroup>
3637

3738
<ItemGroup>

sources/tools/Stride.FreeImage/Classes/FreeImageBitmap.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3329,6 +3329,15 @@ public uint ApplyPaletteIndexMapping(byte[] srcindices, byte[] dstindices, uint
33293329
}
33303330
return FreeImage.ApplyPaletteIndexMapping(dib, srcindices, dstindices, (uint)srcindices.Length, swap);
33313331
}
3332+
3333+
/// <summary>
3334+
/// Converts a bitmap to 32 bits. A clone of the input bitmap is returned for 32-bit bitmaps.
3335+
/// </summary>
3336+
/// <returns>The <see cref="FreeImageBitmap"/> this method creates.</returns>
3337+
public FreeImageBitmap ConvertTo32Bits()
3338+
{
3339+
return new FreeImageBitmap(FreeImage.ConvertTo32Bits(dib));
3340+
}
33323341

33333342
/// <summary>
33343343
/// Swaps two specified palette indices on a 1-, 4- or 8-bit palletized image.

0 commit comments

Comments
 (0)