Move platform-specific native library logic to PlatformCompat

This commit is contained in:
Ben Olden-Cooligan 2022-06-18 11:59:31 -07:00
parent fcf5e335ec
commit a166dd6766
16 changed files with 142 additions and 124 deletions

View File

@ -43,7 +43,7 @@ public class CommandLineIntegrationTests : ContextualTexts
OutputPath = $"{FolderPath}/test.pdf",
Verbose = true
},
BarcodeTestsData.color_image);
SharedData.color_image);
PdfAsserts.AssertPageCount(1, $"{FolderPath}/test.pdf");
AssertRecoveryCleanedUp();
}
@ -100,7 +100,7 @@ public class CommandLineIntegrationTests : ContextualTexts
public override void Load()
{
Rebind<ImageContext>().ToConstant(_imageContext);
// TODO: Bind TesseractLanguageManager
// TODO: Bind TesseractLanguageManager or at least the language data path
Rebind<IScanDriverFactory>().ToConstant(_scanDriverFactory);
Rebind<IScanBridgeFactory>().To<InProcScanBridgeFactory>();
Rebind<ConsoleOutput>().ToSelf().WithConstructorArgument("writer", new TestOutputTextWriter(_testOutputHelper));

View File

@ -12,7 +12,7 @@ public class BarcodeTests
[Fact]
public void DetectPatchT()
{
var image = new GdiImage(BarcodeTestsData.patcht);
var image = new GdiImage(SharedData.patcht);
var detection = BarcodeDetector.Detect(image, new BarcodeDetectionOptions
{
DetectBarcodes = true,
@ -41,7 +41,7 @@ public class BarcodeTests
[Fact]
public void DetectNothing()
{
var image = new GdiImage(BarcodeTestsData.color_image);
var image = new GdiImage(SharedData.color_image);
var detection = BarcodeDetector.Detect(image, new BarcodeDetectionOptions
{
DetectBarcodes = true,

View File

@ -60,16 +60,6 @@ namespace NAPS2.Sdk.Tests.Images {
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
public static System.Drawing.Bitmap color_image {
get {
object obj = ResourceManager.GetObject("color_image", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
@ -79,15 +69,5 @@ namespace NAPS2.Sdk.Tests.Images {
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
public static System.Drawing.Bitmap patcht {
get {
object obj = ResourceManager.GetObject("patcht", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
}
}

View File

@ -118,13 +118,7 @@
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="patcht" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\patcht.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="image_upc_barcode" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\image_upc_barcode.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="color_image" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\color_image.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
</root>

View File

@ -13,8 +13,8 @@ public class PdfiumNativeLibrary : NativeLibrary
public const int FPDF_PRINTING = 0x800;
public const int FPDF_REVERSE_BYTE_ORDER = 0x10;
public PdfiumNativeLibrary(string basePath, string win32Path, string win64Path, string linuxPath, string osxPath)
: base(basePath, win32Path, win64Path, linuxPath, osxPath)
public PdfiumNativeLibrary(string libraryPath)
: base(libraryPath)
{
}

View File

@ -7,11 +7,12 @@ public class PdfiumPdfRenderer : IPdfRenderer
private const int RENDER_FLAGS = PdfiumNativeLibrary.FPDF_PRINTING;
private const uint COLOR_WHITE = uint.MaxValue;
private static readonly Lazy<PdfiumNativeLibrary> LazyNativeLib = new Lazy<PdfiumNativeLibrary>(() =>
private static readonly Lazy<PdfiumNativeLibrary> LazyNativeLib = new(() =>
{
var assemblyLocation = Assembly.GetExecutingAssembly().Location;
var assemblyFolder = System.IO.Path.GetDirectoryName(assemblyLocation);
var nativeLib = new PdfiumNativeLibrary(assemblyFolder, "_win32/pdfium.dll", "_win64/pdfium.dll", "_linux/libpdfium.so", "_osx/libpdfium.dylib");
var assemblyFolder = Path.GetDirectoryName(assemblyLocation);
var libraryPath = Path.Combine(assemblyFolder, PlatformCompat.System.PdfiumLibraryPath);
var nativeLib = new PdfiumNativeLibrary(libraryPath);
nativeLib.FPDF_InitLibrary();
return nativeLib;
});

View File

@ -13,4 +13,10 @@ public interface ISystemCompat
bool UseUnixFontResolver { get; }
bool IsWia20Supported { get; }
string PdfiumLibraryPath { get; }
IntPtr LoadLibrary(string path);
IntPtr LoadSymbol(IntPtr libraryHandle, string symbol);
}

View File

@ -0,0 +1,15 @@
using System.Runtime.InteropServices;
namespace NAPS2.Platform.Linux;
public static class LinuxInterop
{
[DllImport("libdl.so")]
public static extern IntPtr dlopen(string filename, int flags);
[DllImport("libdl.so")]
public static extern IntPtr dlerror();
[DllImport("libdl.so")]
public static extern IntPtr dlsym(IntPtr handle, string symbol);
}

View File

@ -1,7 +1,12 @@
namespace NAPS2.Platform;
using NAPS2.Platform.Linux;
namespace NAPS2.Platform;
public class LinuxSystemCompat : ISystemCompat
{
private const int RTLD_LAZY = 1;
private const int RTLD_GLOBAL = 8;
public bool IsWiaDriverSupported => false;
public bool IsWia20Supported => false;
@ -13,4 +18,10 @@ public class LinuxSystemCompat : ISystemCompat
public bool CanUseWin32 => false;
public bool UseUnixFontResolver => true;
public string PdfiumLibraryPath => "_linux/libpdfium.so";
public IntPtr LoadLibrary(string path) => LinuxInterop.dlopen(path, RTLD_LAZY | RTLD_GLOBAL);
public IntPtr LoadSymbol(IntPtr libraryHandle, string symbol) => LinuxInterop.dlsym(libraryHandle, symbol);
}

View File

@ -0,0 +1,15 @@
using System.Runtime.InteropServices;
namespace NAPS2.Platform.Mac;
public static class OsxInterop
{
[DllImport("libSystem.dylib")]
public static extern IntPtr dlopen(string filename, int flags);
[DllImport("libSystem.dylib")]
public static extern IntPtr dlerror();
[DllImport("libSystem.dylib")]
public static extern IntPtr dlsym(IntPtr handle, string symbol);
}

View File

@ -0,0 +1,27 @@
using NAPS2.Platform.Mac;
namespace NAPS2.Platform;
public class MacSystemCompat : ISystemCompat
{
private const int RTLD_LAZY = 1;
private const int RTLD_GLOBAL = 8;
public bool IsWiaDriverSupported => false;
public bool IsWia20Supported => false;
public bool IsTwainDriverSupported => true;
public bool IsSaneDriverSupported => false;
public bool CanUseWin32 => false;
public bool UseUnixFontResolver => true;
public string PdfiumLibraryPath => "_osx/libpdfium.dylib";
public IntPtr LoadLibrary(string path) => OsxInterop.dlopen(path, RTLD_LAZY | RTLD_GLOBAL);
public IntPtr LoadSymbol(IntPtr libraryHandle, string symbol) => OsxInterop.dlsym(libraryHandle, symbol);
}

View File

@ -18,11 +18,19 @@ public class PlatformCompat
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
{
_systemCompat = new WindowsSystemCompat();
_systemCompat = Environment.Is64BitProcess ? new Windows64SystemCompat() : new Windows32SystemCompat();
}
else if (Environment.OSVersion.Platform == PlatformID.Unix)
{
_systemCompat = new LinuxSystemCompat();
}
else if (Environment.OSVersion.Platform == PlatformID.MacOSX)
{
_systemCompat = new MacSystemCompat();
}
else
{
_systemCompat = new LinuxSystemCompat();
throw new InvalidOperationException("Unsupported platform");
}
}

View File

@ -0,0 +1,22 @@
using NAPS2.Platform.Windows;
namespace NAPS2.Platform;
public class Windows32SystemCompat : WindowsSystemCompat
{
public override string PdfiumLibraryPath => "_win32/pdfium.dll";
public override IntPtr LoadSymbol(IntPtr libraryHandle, string symbol)
{
// Names can be mangled in 32-bit
for (int i = 0; i < 128; i += 4)
{
var address = Win32.GetProcAddress(libraryHandle, $"_{symbol}@{i}");
if (address != IntPtr.Zero)
{
return address;
}
}
return IntPtr.Zero;
}
}

View File

@ -0,0 +1,13 @@
using NAPS2.Platform.Windows;
namespace NAPS2.Platform;
public class Windows64SystemCompat : WindowsSystemCompat
{
public override string PdfiumLibraryPath => "_win64/pdfium.dll";
public override IntPtr LoadSymbol(IntPtr libraryHandle, string symbol)
{
return Win32.GetProcAddress(libraryHandle, symbol);
}
}

View File

@ -1,8 +1,9 @@
using NAPS2.Dependencies;
using NAPS2.Platform.Windows;
namespace NAPS2.Platform;
public class WindowsSystemCompat : ISystemCompat
public abstract class WindowsSystemCompat : ISystemCompat
{
public bool IsWiaDriverSupported => true;
@ -15,4 +16,10 @@ public class WindowsSystemCompat : ISystemCompat
public bool CanUseWin32 => true;
public bool UseUnixFontResolver => false;
public abstract string PdfiumLibraryPath { get; }
public IntPtr LoadLibrary(string path) => Win32.LoadLibrary(path);
public abstract IntPtr LoadSymbol(IntPtr libraryHandle, string symbol);
}

View File

@ -1,30 +1,15 @@
using System.Runtime.InteropServices;
using NAPS2.Platform.Windows;
namespace NAPS2.Unmanaged;
public class NativeLibrary
{
private const int RTLD_LAZY = 1;
private const int RTLD_GLOBAL = 8;
private readonly string _basePath;
private readonly string _win32Path;
private readonly string _win64Path;
private readonly string _linuxPath;
private readonly string _osxPath;
private readonly Dictionary<Type, object> _funcCache = new Dictionary<Type, object>();
private readonly Dictionary<Type, object> _funcCache = new();
private readonly Lazy<IntPtr> _libraryHandle;
public NativeLibrary(string basePath, string win32Path, string win64Path, string linuxPath, string osxPath)
public NativeLibrary(string libraryPath)
{
_basePath = basePath;
_win32Path = win32Path;
_win64Path = win64Path;
_linuxPath = linuxPath;
_osxPath = osxPath;
_libraryHandle = new Lazy<IntPtr>(LoadLibrary);
_libraryHandle = new Lazy<IntPtr>(() => PlatformCompat.System.LoadLibrary(libraryPath));
}
public IntPtr LibraryHandle => _libraryHandle.Value;
@ -34,75 +19,9 @@ public class NativeLibrary
return (T)_funcCache.Get(typeof(T), () => Marshal.GetDelegateForFunctionPointer<T>(LoadFunc<T>()));
}
private IntPtr LoadLibrary()
{
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
{
var path = Environment.Is64BitProcess ? _win64Path : _win32Path;
return Win32.LoadLibrary(Path.Combine(_basePath, path));
}
if (Environment.OSVersion.Platform == PlatformID.Unix)
{
return LinuxInterop.dlopen(Path.Combine(_basePath, _linuxPath), RTLD_LAZY | RTLD_GLOBAL);
}
if (Environment.OSVersion.Platform == PlatformID.MacOSX)
{
return OsxInterop.dlopen(Path.Combine(_basePath, _osxPath), RTLD_LAZY | RTLD_GLOBAL);
}
return IntPtr.Zero;
}
private IntPtr LoadFunc<T>()
{
var symbol = typeof(T).Name.Replace("_delegate", "");
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
{
if (Environment.Is64BitProcess)
{
return Win32.GetProcAddress(LibraryHandle, symbol);
}
// Names can be mangled in 32-bit
for (int i = 0; i < 128; i += 4)
{
var address = Win32.GetProcAddress(LibraryHandle, $"_{symbol}@{i}");
if (address != IntPtr.Zero)
{
return address;
}
}
}
if (Environment.OSVersion.Platform == PlatformID.Unix)
{
return LinuxInterop.dlsym(LibraryHandle, symbol);
}
if (Environment.OSVersion.Platform == PlatformID.MacOSX)
{
return OsxInterop.dlsym(LibraryHandle, symbol);
}
return IntPtr.Zero;
}
private static class LinuxInterop
{
[DllImport("libdl.so")]
public static extern IntPtr dlopen(string filename, int flags);
[DllImport("libdl.so")]
public static extern IntPtr dlerror();
[DllImport("libdl.so")]
public static extern IntPtr dlsym(IntPtr handle, string symbol);
}
private static class OsxInterop
{
[DllImport("libSystem.dylib")]
public static extern IntPtr dlopen(string filename, int flags);
[DllImport("libSystem.dylib")]
public static extern IntPtr dlerror();
[DllImport("libSystem.dylib")]
public static extern IntPtr dlsym(IntPtr handle, string symbol);
return PlatformCompat.System.LoadSymbol(LibraryHandle, symbol);
}
}