Begin work on Quik.Media.Stb
This commit is contained in:
parent
648f44f12d
commit
c3a815171b
37
Quik.Media.Stb/QFontStbtt.cs
Normal file
37
Quik.Media.Stb/QFontStbtt.cs
Normal file
@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using static StbTrueTypeSharp.StbTrueType;
|
||||
using Quik.Media.Color;
|
||||
|
||||
namespace Quik.Media.Stb
|
||||
{
|
||||
public class QFontStbtt : QFont
|
||||
{
|
||||
public override FontInfo Info => throw new NotImplementedException();
|
||||
|
||||
public QFontStbtt(Stream source)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override QGlyphMetrics[] GetMetricsForPage(int codepage)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override QGlyphMetrics GetMetricsForRune(int rune)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override bool HasRune(int rune)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override QImage RenderPage(int codepage, float resolution, bool sdf)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
93
Quik.Media.Stb/QImageStbi.cs
Normal file
93
Quik.Media.Stb/QImageStbi.cs
Normal file
@ -0,0 +1,93 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using Quik.Media;
|
||||
using Quik.Media.Color;
|
||||
using Quik.Stb;
|
||||
|
||||
namespace Quik.Media.Stb
|
||||
{
|
||||
public unsafe class QImageStbi : QImage
|
||||
{
|
||||
private readonly StbImage image;
|
||||
private ImageBuffer buffer;
|
||||
|
||||
public override int Width => image.Width;
|
||||
|
||||
public override int Height => image.Height;
|
||||
|
||||
public override int Depth => 1;
|
||||
public override QImageFormat InternalFormat => Stb2QImageFormat(image.Format);
|
||||
|
||||
public QImageStbi(Stream source)
|
||||
{
|
||||
// According to the stbi documentation, only a specific type of PNG
|
||||
// files are premultiplied out of the box (iPhone PNG). Take the
|
||||
// precision loss L and move on.
|
||||
StbImage.FlipVerticallyOnLoad = true;
|
||||
StbImage.UnpremultiplyOnLoad = true;
|
||||
|
||||
image = StbImage.Load(source);
|
||||
}
|
||||
|
||||
public static QImageFormat Stb2QImageFormat(StbiImageFormat src)
|
||||
{
|
||||
switch (src)
|
||||
{
|
||||
case StbiImageFormat.Grey: return QImageFormat.RedU8;
|
||||
case StbiImageFormat.Rgb: return QImageFormat.RgbU8;
|
||||
case StbiImageFormat.Rgba: return QImageFormat.RgbaU8;
|
||||
case StbiImageFormat.GreyAlpha: return QImageFormat.RaU8;
|
||||
default: return QImageFormat.Undefined;
|
||||
}
|
||||
}
|
||||
|
||||
public override void LockBits2d(out QImageLock imageLock, QImageLockOptions options)
|
||||
{
|
||||
if (options.MipLevel > 0) throw new Exception("This image has no mip levels.");
|
||||
|
||||
buffer?.Dispose();
|
||||
buffer = new ImageBuffer(options.Format, Width, Height);
|
||||
QImageLock dst = buffer.Lock();
|
||||
|
||||
byte *srcPtr = (byte*)image.ImagePointer;
|
||||
QImageLock src = new QImageLock(InternalFormat, Width, Height, 1, (IntPtr)srcPtr);
|
||||
FormatConvert.Convert(dst, src);
|
||||
|
||||
if (options.Premultiply)
|
||||
{
|
||||
FormatConvert.Premultiply(dst);
|
||||
}
|
||||
|
||||
imageLock = dst;
|
||||
}
|
||||
|
||||
public override void LockBits3d(out QImageLock imageLock, QImageLockOptions options)
|
||||
{
|
||||
LockBits2d(out imageLock, options);
|
||||
}
|
||||
|
||||
public override void LockBits3d(out QImageLock imageLock, QImageLockOptions options, int depth)
|
||||
{
|
||||
if (depth != 1) throw new ArgumentOutOfRangeException(nameof(depth));
|
||||
|
||||
LockBits2d(out imageLock, options);
|
||||
}
|
||||
|
||||
public override void UnlockBits()
|
||||
{
|
||||
buffer.Unlock();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
buffer?.Dispose();
|
||||
image.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
21
Quik.Media.Stb/Quik.Media.Stb.csproj
Normal file
21
Quik.Media.Stb/Quik.Media.Stb.csproj
Normal file
@ -0,0 +1,21 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<LanguageVersion>7.3</LanguageVersion>
|
||||
<Nullable>disable</Nullable>
|
||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="StbImageSharp" Version="2.27.13" />
|
||||
<PackageReference Include="StbTrueTypeSharp" Version="1.26.11" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Quik\Quik.csproj" />
|
||||
<ProjectReference Include="..\Quik.StbImage\Quik.StbImage.csproj" />
|
||||
<ProjectReference Include="..\Quik.StbTrueType\Quik.StbTrueType.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
152
Quik.Media.Stb/StbMediaLoader.cs
Normal file
152
Quik.Media.Stb/StbMediaLoader.cs
Normal file
@ -0,0 +1,152 @@
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using Quik.Media;
|
||||
|
||||
namespace Quik.Media.Stb
|
||||
{
|
||||
public class StbMediaLoader : MediaLoader<string>, MediaLoader<Uri>, MediaLoader<FileInfo>, MediaLoader<FontInfo>
|
||||
{
|
||||
public bool AllowRemoteTransfers { get; set; } = false;
|
||||
private readonly ArrayPool<byte> ByteArrays = ArrayPool<byte>.Create();
|
||||
|
||||
public IDisposable GetMedia(object key, MediaHint hint)
|
||||
{
|
||||
Type t = key.GetType();
|
||||
/**/ if (t == typeof(string))
|
||||
{
|
||||
return GetMedia((string)key, hint);
|
||||
}
|
||||
else if (t == typeof(Uri))
|
||||
{
|
||||
return GetMedia((Uri)key, hint);
|
||||
}
|
||||
else if (t == typeof(FileInfo))
|
||||
{
|
||||
return GetMedia((FileInfo)key, hint);
|
||||
}
|
||||
else if (t == typeof(FontInfo))
|
||||
{
|
||||
return GetMedia((FontInfo)key, hint);
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public IDisposable GetMedia(Uri uri, MediaHint hint)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public IDisposable GetMedia(string str, MediaHint hint)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public IDisposable GetMedia(FileInfo file, MediaHint hint)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public IDisposable GetMedia(FontInfo key, MediaHint hint)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Stream OpenResource(FileInfo file)
|
||||
{
|
||||
if (file.Exists)
|
||||
{
|
||||
return file.Open(FileMode.Open);
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public Stream OpenResource(Uri uri)
|
||||
{
|
||||
switch (uri.Scheme)
|
||||
{
|
||||
case "http":
|
||||
case "https":
|
||||
if (!AllowRemoteTransfers) return null;
|
||||
|
||||
try
|
||||
{
|
||||
WebRequest request = HttpWebRequest.Create(uri);
|
||||
WebResponse response = request.GetResponse();
|
||||
MemoryStream stream = new MemoryStream();
|
||||
|
||||
response.GetResponseStream().CopyTo(stream);
|
||||
response.Close();
|
||||
|
||||
stream.Position = 0;
|
||||
return stream;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
case "file":
|
||||
return OpenResource(new FileInfo(uri.AbsolutePath));
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public Stream OpenResource(string key)
|
||||
{
|
||||
if (File.Exists(key))
|
||||
{
|
||||
return File.Open(key, FileMode.Open);
|
||||
}
|
||||
else if (Uri.TryCreate(key, UriKind.RelativeOrAbsolute, out Uri uri))
|
||||
{
|
||||
return OpenResource(uri);
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
MediaHint InferMedia(Stream str, MediaHint hint)
|
||||
{
|
||||
if (hint != MediaHint.None)
|
||||
{
|
||||
return hint;
|
||||
}
|
||||
|
||||
byte[] array = ByteArrays.Rent(4);
|
||||
str.Read(array, 0, 4);
|
||||
str.Position = 0;
|
||||
|
||||
foreach (var(type, seq) in MediaTypes)
|
||||
{
|
||||
if (seq.SequenceEqual(array))
|
||||
return hint;
|
||||
}
|
||||
|
||||
return MediaHint.None;
|
||||
}
|
||||
|
||||
private readonly (MediaHint, byte[])[] MediaTypes = new (MediaHint, byte[])[] {
|
||||
(MediaHint.Image, new byte[] { 0x42, 0x4d }), /* .bmp `BM` */
|
||||
(MediaHint.Image, new byte[] { 0x47, 0x49, 0x46, 0x38 }), /* .gif `GIF8` */
|
||||
(MediaHint.Image, new byte[] { 0xff, 0xd8, 0xff, 0xe0 }), /* .jpg (JFIF) */
|
||||
(MediaHint.Image, new byte[] { 0xff, 0xd8, 0xff, 0xe1 }), /* .jpg (EXIF) */
|
||||
(MediaHint.Image, new byte[] { 0x89, 0x50, 0x4e, 0x47 }), /* .png `.PNG `*/
|
||||
(MediaHint.Image, new byte[] { 0x4d, 0x4d, 0x00, 0x2a }), /* .tif (motorola) */
|
||||
(MediaHint.Image, new byte[] { 0x49, 0x49, 0x2a, 0x00 }), /* .tif (intel) */
|
||||
(MediaHint.Font, new byte[] { 0x00, 0x01, 0x00, 0x00 }), /* .ttf */
|
||||
(MediaHint.Font, new byte[] { 0x4F, 0x54, 0x54, 0x4F }), /* .otf */
|
||||
};
|
||||
}
|
||||
}
|
@ -118,9 +118,9 @@ namespace Quik.Stb
|
||||
/// <param name="stream">The stream to load from.</param>
|
||||
/// <param name="format">The desired image format.</param>
|
||||
/// <returns>The image object.</returns>
|
||||
public static StbImage Load(Stream stream, StbiImageFormat format = StbiImageFormat.Default)
|
||||
public static StbImage Load(Stream stream, StbiImageFormat format = StbiImageFormat.Default, bool isFloat = false)
|
||||
{
|
||||
if (TryLoad(out StbImage image, stream, format))
|
||||
if (TryLoad(out StbImage image, stream, format, isFloat))
|
||||
{
|
||||
return image;
|
||||
}
|
||||
@ -128,5 +128,17 @@ namespace Quik.Stb
|
||||
string reason = Marshal.PtrToStringUTF8((IntPtr)Stbi.failure_reason());
|
||||
throw new Exception($"Failed to load image: {reason}");
|
||||
}
|
||||
|
||||
public bool IsLoadable(Stream stream)
|
||||
{
|
||||
int x, y, iFormat;
|
||||
StbiStreamWrapper wrapper = new StbiStreamWrapper(stream, true);
|
||||
wrapper.CreateCallbacks(out stbi_io_callbacks cb);
|
||||
|
||||
stream.Position = 0;
|
||||
int result = Stbi.info_from_callbacks(&cb, null, &x, &y, &iFormat);
|
||||
|
||||
return result != 0;
|
||||
}
|
||||
}
|
||||
}
|
14
Quik.sln
14
Quik.sln
@ -13,6 +13,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{5E87AF9C
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Quik.StbImage.Tests", "tests\Quik.StbImage.Tests\Quik.StbImage.Tests.csproj", "{AFF181CF-D51E-4E16-B3C6-38ED1E1FF615}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Quik.Media.Stb", "Quik.Media.Stb\Quik.Media.Stb.csproj", "{3D354BE0-42A7-45C4-AAEA-B0F8963A5745}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -83,6 +85,18 @@ Global
|
||||
{AFF181CF-D51E-4E16-B3C6-38ED1E1FF615}.Release|x64.Build.0 = Release|Any CPU
|
||||
{AFF181CF-D51E-4E16-B3C6-38ED1E1FF615}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{AFF181CF-D51E-4E16-B3C6-38ED1E1FF615}.Release|x86.Build.0 = Release|Any CPU
|
||||
{3D354BE0-42A7-45C4-AAEA-B0F8963A5745}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3D354BE0-42A7-45C4-AAEA-B0F8963A5745}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3D354BE0-42A7-45C4-AAEA-B0F8963A5745}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{3D354BE0-42A7-45C4-AAEA-B0F8963A5745}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{3D354BE0-42A7-45C4-AAEA-B0F8963A5745}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{3D354BE0-42A7-45C4-AAEA-B0F8963A5745}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{3D354BE0-42A7-45C4-AAEA-B0F8963A5745}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3D354BE0-42A7-45C4-AAEA-B0F8963A5745}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3D354BE0-42A7-45C4-AAEA-B0F8963A5745}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{3D354BE0-42A7-45C4-AAEA-B0F8963A5745}.Release|x64.Build.0 = Release|Any CPU
|
||||
{3D354BE0-42A7-45C4-AAEA-B0F8963A5745}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{3D354BE0-42A7-45C4-AAEA-B0F8963A5745}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{AFF181CF-D51E-4E16-B3C6-38ED1E1FF615} = {5E87AF9C-AC12-4E48-99B1-CBEC0C97B624}
|
||||
|
@ -12,8 +12,8 @@ namespace Quik.StbImage.Tests
|
||||
[TestMethod("Set Global Options")]
|
||||
public void SetGlobals()
|
||||
{
|
||||
Stbi.set_flip_vertically_on_load(1);
|
||||
Stbi.set_unpremultiply_on_load(1);
|
||||
Quik.Stb.StbImage.FlipVerticallyOnLoad = true;
|
||||
Quik.Stb.StbImage.UnpremultiplyOnLoad = true;
|
||||
}
|
||||
|
||||
private StbiStreamWrapper PrepareImage(string path, out stbi_io_callbacks cb)
|
||||
|
Loading…
Reference in New Issue
Block a user