Skip to content

Commit d97884b

Browse files
committed
feat: Xplat support for image loading and saving from memory
1 parent ca98fca commit d97884b

File tree

3 files changed

+116
-125
lines changed

3 files changed

+116
-125
lines changed
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
2+
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
3+
#if STRIDE_PLATFORM_DESKTOP
4+
using System;
5+
using System.IO;
6+
using System.Runtime.InteropServices;
7+
using FreeImageAPI;
8+
using Stride.Core;
9+
using RotateFlipType = FreeImageAPI.RotateFlipType;
10+
11+
namespace Stride.Graphics
12+
{
13+
/// <summary>
14+
/// This class is responsible to provide image loader for png, gif, bmp.
15+
/// </summary>
16+
partial class StandardImageHelper
17+
{
18+
static StandardImageHelper()
19+
{
20+
NativeLibraryHelper.PreloadLibrary("freeimage", typeof(StandardImageHelper));
21+
}
22+
23+
public static unsafe Image LoadFromMemory(IntPtr pSource, int size, bool makeACopy, GCHandle? handle)
24+
{
25+
using var memoryStream = new UnmanagedMemoryStream((byte*)pSource, size, capacity: size, access: FileAccess.Read);
26+
using var bitmap = FreeImageBitmap.FromStream(memoryStream);
27+
28+
bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY);
29+
bitmap.ConvertColorDepth(FREE_IMAGE_COLOR_DEPTH.FICD_32_BPP);
30+
31+
var image = Image.New2D(bitmap.Width, bitmap.Height, 1, PixelFormat.B8G8R8A8_UNorm, 1, bitmap.Line);
32+
33+
try
34+
{
35+
// TODO: Test if still necessary
36+
// Directly load image as RGBA instead of BGRA, because OpenGL ES devices don't support it out of the box (extension).
37+
Utilities.CopyWithAlignmentFallback((void*)image.PixelBuffer[0].DataPointer, (void*)bitmap.Bits, (uint)image.PixelBuffer[0].BufferStride);
38+
}
39+
finally
40+
{
41+
if (handle != null)
42+
handle.Value.Free();
43+
else if (!makeACopy)
44+
Utilities.FreeMemory(pSource);
45+
}
46+
47+
return image;
48+
}
49+
50+
public static void SaveGifFromMemory(PixelBuffer[] pixelBuffers, int count, ImageDescription description, Stream imageStream)
51+
{
52+
SaveFromMemory(pixelBuffers, description, imageStream, FREE_IMAGE_FORMAT.FIF_GIF);
53+
}
54+
55+
public static void SaveTiffFromMemory(PixelBuffer[] pixelBuffers, int count, ImageDescription description, Stream imageStream)
56+
{
57+
SaveFromMemory(pixelBuffers, description, imageStream, FREE_IMAGE_FORMAT.FIF_TIFF);
58+
}
59+
60+
public static void SaveBmpFromMemory(PixelBuffer[] pixelBuffers, int count, ImageDescription description, Stream imageStream)
61+
{
62+
SaveFromMemory(pixelBuffers, description, imageStream, FREE_IMAGE_FORMAT.FIF_BMP);
63+
}
64+
65+
public static void SaveJpgFromMemory(PixelBuffer[] pixelBuffers, int count, ImageDescription description, Stream imageStream)
66+
{
67+
SaveFromMemory(pixelBuffers, description, imageStream, FREE_IMAGE_FORMAT.FIF_BMP);
68+
}
69+
70+
public static void SavePngFromMemory(PixelBuffer[] pixelBuffers, int count, ImageDescription description, Stream imageStream)
71+
{
72+
SaveFromMemory(pixelBuffers, description, imageStream, FREE_IMAGE_FORMAT.FIF_PNG);
73+
}
74+
75+
public static void SaveWmpFromMemory(PixelBuffer[] pixelBuffers, int count, ImageDescription description, Stream imageStream)
76+
{
77+
throw new NotImplementedException();
78+
}
79+
80+
private static unsafe void SaveFromMemory(PixelBuffer[] pixelBuffers, ImageDescription description, Stream imageStream, FREE_IMAGE_FORMAT imageFormat)
81+
{
82+
using var bitmap = new FreeImageBitmap(description.Width, description.Height);
83+
bitmap.ConvertColorDepth(FREE_IMAGE_COLOR_DEPTH.FICD_32_BPP);
84+
85+
// Copy memory
86+
var format = description.Format;
87+
if (format is PixelFormat.R8G8B8A8_UNorm or PixelFormat.R8G8B8A8_UNorm_SRgb)
88+
{
89+
CopyMemoryBGRA(bitmap.Bits, pixelBuffers[0].DataPointer, pixelBuffers[0].BufferStride);
90+
}
91+
else if (format is PixelFormat.B8G8R8A8_UNorm or PixelFormat.B8G8R8A8_UNorm_SRgb)
92+
{
93+
Utilities.CopyWithAlignmentFallback((void*)bitmap.Bits, (void*)pixelBuffers[0].DataPointer, (uint)pixelBuffers[0].BufferStride);
94+
}
95+
else if (format is PixelFormat.R8_UNorm or PixelFormat.A8_UNorm)
96+
{
97+
// TODO Ideally we will want to support grayscale images, but the SpriteBatch can only render RGBA for now
98+
// so convert the grayscale image as an RGBA and save it
99+
CopyMemoryRRR1(bitmap.Bits, pixelBuffers[0].DataPointer, pixelBuffers[0].BufferStride);
100+
}
101+
else
102+
{
103+
throw new ArgumentException(
104+
message:
105+
$"The pixel format {format} is not supported. Supported formats are {PixelFormat.B8G8R8A8_UNorm}, {PixelFormat.B8G8R8A8_UNorm_SRgb}, {PixelFormat.R8G8B8A8_UNorm}, {PixelFormat.R8G8B8A8_UNorm_SRgb}, {PixelFormat.R8_UNorm}, {PixelFormat.A8_UNorm}",
106+
paramName: nameof(description));
107+
}
108+
109+
// Save
110+
bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY);
111+
bitmap.Save(imageStream, imageFormat);
112+
}
113+
}
114+
}
115+
#endif

sources/engine/Stride/Graphics/StandardImageHelper.Windows.cs

Lines changed: 0 additions & 125 deletions
This file was deleted.

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>

0 commit comments

Comments
 (0)