mirror of
https://github.com/soukoku/ntwain.git
synced 2026-02-25 13:04:07 +08:00
Merge pull request #75 from soukoku/Win32-native-experiments
Win32 native experiments
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
<TargetFramework>net8.0-windows</TargetFramework>
|
<TargetFramework>net10.0-windows7.0</TargetFramework>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<UseWindowsForms>true</UseWindowsForms>
|
<UseWindowsForms>true</UseWindowsForms>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
|||||||
@@ -127,13 +127,13 @@ namespace WinConsole32
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int xferCount = 0;
|
static int xferCount = 0;
|
||||||
static Stopwatch watch;
|
static Stopwatch watch = new Stopwatch();
|
||||||
private static void Session_Transferred(TwainAppSession twain, TransferredEventArgs e)
|
private static void Session_Transferred(TwainAppSession twain, TransferredEventArgs e)
|
||||||
{
|
{
|
||||||
if (e.Data != null)
|
if (e.Data != null)
|
||||||
{
|
{
|
||||||
var saveFile = $"twain_{DateTime.Now:yyyyMMdd_HHmmss}_{xferCount}";
|
var saveFile = $"twain_{DateTime.Now:yyyyMMdd_HHmmss}_{xferCount}";
|
||||||
Console.WriteLine("SUCCESS! Got twain memory data #{0} on thread {1}, saving to {saveFile}.", ++xferCount, Environment.CurrentManagedThreadId, saveFile);
|
Console.WriteLine($"SUCCESS! Got twain memory data #{++xferCount} on thread {Environment.CurrentManagedThreadId}, saving to {saveFile}.");
|
||||||
|
|
||||||
using (var img = new ImageMagick.MagickImage(e.Data.AsStream()))
|
using (var img = new ImageMagick.MagickImage(e.Data.AsStream()))
|
||||||
{
|
{
|
||||||
@@ -157,11 +157,11 @@ namespace WinConsole32
|
|||||||
else if (e.FileInfo != null)
|
else if (e.FileInfo != null)
|
||||||
{
|
{
|
||||||
var fi = e.FileInfo.Value;
|
var fi = e.FileInfo.Value;
|
||||||
Console.WriteLine("SUCCESS! Got twain file data #{0} on thread {1} as {saveFile}.", ++xferCount, Environment.CurrentManagedThreadId, fi.FileName);
|
Console.WriteLine($"SUCCESS! Got twain file data #{++xferCount} on thread {Environment.CurrentManagedThreadId} as {fi.FileName}.");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Console.WriteLine("BUMMER! No twain data #{0} on thread {1}.", ++xferCount, Environment.CurrentManagedThreadId);
|
Console.WriteLine($"BUMMER! No twain data #{++xferCount} on thread {Environment.CurrentManagedThreadId}.");
|
||||||
}
|
}
|
||||||
e.Dispose();
|
e.Dispose();
|
||||||
}
|
}
|
||||||
@@ -199,10 +199,10 @@ namespace WinConsole32
|
|||||||
twain.Caps.ICAP_PIXELTYPE.Set(TWPT.RGB);
|
twain.Caps.ICAP_PIXELTYPE.Set(TWPT.RGB);
|
||||||
twain.Caps.ICAP_XRESOLUTION.Set(300f);
|
twain.Caps.ICAP_XRESOLUTION.Set(300f);
|
||||||
twain.Caps.ICAP_YRESOLUTION.Set(300f);
|
twain.Caps.ICAP_YRESOLUTION.Set(300f);
|
||||||
twain.Caps.CAP_XFERCOUNT.Set(100);
|
twain.Caps.CAP_XFERCOUNT.Set(4);
|
||||||
|
|
||||||
xferCount = 0;
|
xferCount = 0;
|
||||||
watch = Stopwatch.StartNew();
|
watch.Restart();
|
||||||
var rc = twain.EnableSource(true, false);
|
var rc = twain.EnableSource(true, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Magick.NET-Q8-AnyCPU" Version="14.0.0" />
|
<PackageReference Include="Magick.NET-Q8-AnyCPU" Version="14.9.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -202,7 +202,7 @@ namespace WinFormSample
|
|||||||
// color
|
// color
|
||||||
saveFile += ".jpg";
|
saveFile += ".jpg";
|
||||||
format = ImageMagick.MagickFormat.Jpeg;
|
format = ImageMagick.MagickFormat.Jpeg;
|
||||||
img.Quality = _jpegQuality;
|
img.Quality = (uint)_jpegQuality;
|
||||||
}
|
}
|
||||||
if (_saveDisk) img.Write(saveFile);
|
if (_saveDisk) img.Write(saveFile);
|
||||||
else img.Write(new NoOpStream(), format);
|
else img.Write(new NoOpStream(), format);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
<TargetFramework>net8.0-windows</TargetFramework>
|
<TargetFramework>net10.0-windows7.0</TargetFramework>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<UseWindowsForms>true</UseWindowsForms>
|
<UseWindowsForms>true</UseWindowsForms>
|
||||||
<PlatformTarget>x86</PlatformTarget>
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Magick.NET-Q8-x86" Version="13.9.1" />
|
<PackageReference Include="Magick.NET-Q8-x86" Version="14.9.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
<TargetFramework>net8.0-windows</TargetFramework>
|
<TargetFramework>net10.0-windows7.0</TargetFramework>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<UseWindowsForms>true</UseWindowsForms>
|
<UseWindowsForms>true</UseWindowsForms>
|
||||||
<PlatformTarget>x64</PlatformTarget>
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Magick.NET-Q8-x64" Version="13.9.1" />
|
<PackageReference Include="Magick.NET-Q8-x64" Version="14.9.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<!--change these in each release-->
|
<!--change these in each release-->
|
||||||
<VersionPrefix>4.0.0.0</VersionPrefix>
|
<VersionPrefix>4.0.0.0</VersionPrefix>
|
||||||
<VersionSuffix>alpha.13</VersionSuffix>
|
<VersionSuffix>alpha.14</VersionSuffix>
|
||||||
|
|
||||||
<!--keep it the same until major # changes-->
|
<!--keep it the same until major # changes-->
|
||||||
<AssemblyVersion>4.0.0.0</AssemblyVersion>
|
<AssemblyVersion>4.0.0.0</AssemblyVersion>
|
||||||
|
|||||||
+53
-46
@@ -1,52 +1,59 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<PackageId>NTwain</PackageId>
|
<PackageId>NTwain</PackageId>
|
||||||
<Description>Library containing the TWAIN API for dotnet.</Description>
|
<Description>Library containing the TWAIN API for dotnet.</Description>
|
||||||
<TargetFrameworks>net8.0;net8.0-windows;net9.0;net9.0-windows;net462;</TargetFrameworks>
|
<TargetFrameworks>net8.0;net8.0-windows;net9.0;net9.0-windows;net10.0;net10.0-windows;net472;</TargetFrameworks>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition=" '$(TargetFramework)' == 'net462' OR $(TargetFramework.EndsWith('windows'))">
|
<PropertyGroup Condition=" '$(TargetFramework)' == 'net472' OR $(TargetFramework.EndsWith('windows'))">
|
||||||
<UseWindowsForms>true</UseWindowsForms>
|
<UseWindowsForms>true</UseWindowsForms>
|
||||||
<UseWPF>true</UseWPF>
|
<UseWPF>true</UseWPF>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup Condition=" '$(TargetFramework)' == 'net462'">
|
<ItemGroup Condition=" '$(TargetFramework)' == 'net472'">
|
||||||
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
||||||
<!--<PackageReference Include="System.Buffers" Version="4.5.1" />-->
|
<!--<PackageReference Include="System.Buffers" Version="4.5.1" />-->
|
||||||
<PackageReference Include="System.Memory" Version="4.5.5" />
|
<PackageReference Include="System.Memory" Version="4.6.3" />
|
||||||
</ItemGroup>
|
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.1.2" />
|
||||||
<ItemGroup Condition=" '$(TargetFramework)' != 'net462'">
|
</ItemGroup>
|
||||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="8.0.0" />
|
<ItemGroup Condition=" '$(TargetFramework)' != 'net472'">
|
||||||
</ItemGroup>
|
<PackageReference Include="System.Text.Encoding.CodePages" Version="10.0.0" />
|
||||||
<ItemGroup Condition="'$(Configuration)'!='Release'">
|
</ItemGroup>
|
||||||
<None Remove="runtimes\win-x64\native\TWAINDSM.dll" />
|
<ItemGroup Condition="'$(Configuration)'!='Release'">
|
||||||
<None Remove="runtimes\win-x86\native\TWAINDSM.dll" />
|
<None Remove="runtimes\win-x64\native\TWAINDSM.dll" />
|
||||||
</ItemGroup>
|
<None Remove="runtimes\win-x86\native\TWAINDSM.dll" />
|
||||||
<ItemGroup Condition="'$(Configuration)'!='Release'">
|
</ItemGroup>
|
||||||
<Content Include="runtimes\win-x64\native\TWAINDSM.dll">
|
<ItemGroup Condition="'$(Configuration)'!='Release'">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<Content Include="runtimes\win-x64\native\TWAINDSM.dll">
|
||||||
</Content>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
<Content Include="runtimes\win-x86\native\TWAINDSM.dll">
|
</Content>
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<Content Include="runtimes\win-x86\native\TWAINDSM.dll">
|
||||||
</Content>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</ItemGroup>
|
</Content>
|
||||||
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Update="DSM\DSMGenerator.dummy">
|
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.3.242">
|
||||||
<DesignTime>True</DesignTime>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<AutoGen>True</AutoGen>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
<DependentUpon>DSMGenerator.tt</DependentUpon>
|
</PackageReference>
|
||||||
</None>
|
</ItemGroup>
|
||||||
<None Update="DSM\DSMGenerator.tt">
|
|
||||||
<Generator>TextTemplatingFileGenerator</Generator>
|
|
||||||
<LastGenOutput>DSMGenerator.dummy</LastGenOutput>
|
|
||||||
</None>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Service Include="{508349b6-6b84-4df5-91f0-309beebad82d}" />
|
<None Update="DSM\DSMGenerator.dummy">
|
||||||
</ItemGroup>
|
<DesignTime>True</DesignTime>
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DependentUpon>DSMGenerator.tt</DependentUpon>
|
||||||
|
</None>
|
||||||
|
<None Update="DSM\DSMGenerator.tt">
|
||||||
|
<Generator>TextTemplatingFileGenerator</Generator>
|
||||||
|
<LastGenOutput>DSMGenerator.dummy</LastGenOutput>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Service Include="{508349b6-6b84-4df5-91f0-309beebad82d}" />
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
+234
-320
@@ -2,339 +2,253 @@
|
|||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace NTwain.Native
|
namespace Windows.Win32.Graphics.Gdi
|
||||||
{
|
{
|
||||||
// this is a good read
|
// this is a good read
|
||||||
// http://atlc.sourceforge.net/bmp.html
|
// http://atlc.sourceforge.net/bmp.html
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Defines the dimensions and color information for a DIB.
|
|
||||||
/// </summary>
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
|
||||||
struct BITMAPINFO
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Structure that contains information about the dimensions of color format.
|
|
||||||
/// </summary>
|
|
||||||
public BITMAPINFOHEADER bmiHeader;
|
|
||||||
/// <summary>
|
|
||||||
/// This contains one of the following:
|
|
||||||
/// 1. An array of RGBQUAD. The elements of the array that make up the color table.
|
|
||||||
/// 2. An array of 16-bit unsigned integers that specifies indexes into the currently realized logical palette. This use of bmiColors is allowed for functions that use DIBs.
|
|
||||||
/// The number of entries in the array depends on the values of the biBitCount and biClrUsed members of the BITMAPINFOHEADER structure.
|
|
||||||
/// </summary>
|
|
||||||
public IntPtr bmiColors;
|
|
||||||
|
|
||||||
};
|
partial struct BITMAPINFOHEADER
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Structure that contains information about the dimensions and color format of a DIB.
|
|
||||||
/// </summary>
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
|
||||||
struct BITMAPINFOHEADER
|
|
||||||
{
|
|
||||||
#region fields
|
|
||||||
/// <summary>
|
|
||||||
/// The number of bytes required by the structure.
|
|
||||||
/// </summary>
|
|
||||||
public uint biSize;
|
|
||||||
/// <summary>
|
|
||||||
/// The width of the bitmap, in pixels.
|
|
||||||
/// If Compression is JPEG or PNG, the Width member specifies the width of the decompressed
|
|
||||||
/// JPEG or PNG image file, respectively.
|
|
||||||
/// </summary>
|
|
||||||
public int biWidth;
|
|
||||||
/// <summary>
|
|
||||||
/// The height of the bitmap, in pixels. If Height is positive,
|
|
||||||
/// the bitmap is a bottom-up DIB and its origin is the lower-left corner.
|
|
||||||
/// If Height is negative, the bitmap is a top-down DIB and its origin is the upper-left corner.
|
|
||||||
/// If Height is negative, indicating a top-down DIB, Compression must be either RGB or BITFIELDS. Top-down DIBs cannot be compressed.
|
|
||||||
/// If Compression is JPEG or PNG, the Height member specifies the height of the decompressed JPEG or PNG image file, respectively.
|
|
||||||
/// </summary>
|
|
||||||
public int biHeight;
|
|
||||||
/// <summary>
|
|
||||||
/// The number of planes for the target device. This value must be set to 1.
|
|
||||||
/// </summary>
|
|
||||||
public ushort biPlanes;
|
|
||||||
/// <summary>
|
|
||||||
/// The number of bits-per-pixel. The BitCount member
|
|
||||||
/// determines the number of bits that define each pixel and the maximum number of colors in the bitmap.
|
|
||||||
/// </summary>
|
|
||||||
public ushort biBitCount;
|
|
||||||
/// <summary>
|
|
||||||
/// The type of compression for a compressed bottom-up bitmap (top-down DIBs cannot be compressed).
|
|
||||||
/// </summary>
|
|
||||||
public CompressionType biCompression;
|
|
||||||
/// <summary>
|
|
||||||
/// The size, in bytes, of the image. This may be set to zero for RGB bitmaps.
|
|
||||||
/// If Compression is JPEG or PNG, SizeImage indicates the size of the JPEG or PNG image buffer, respectively.
|
|
||||||
/// </summary>
|
|
||||||
public uint biSizeImage;
|
|
||||||
/// <summary>
|
|
||||||
/// The horizontal resolution, in pixels-per-meter, of the target device for the bitmap.
|
|
||||||
/// An application can use this value to select a bitmap from a resource group that
|
|
||||||
/// best matches the characteristics of the current device.
|
|
||||||
/// </summary>
|
|
||||||
public int biXPelsPerMeter;
|
|
||||||
/// <summary>
|
|
||||||
/// The vertical resolution, in pixels-per-meter, of the target device for the bitmap.
|
|
||||||
/// </summary>
|
|
||||||
public int biYPelsPerMeter;
|
|
||||||
/// <summary>
|
|
||||||
/// The number of color indexes in the color table that are actually used by the bitmap.
|
|
||||||
/// If this value is zero, the bitmap uses the maximum number of colors corresponding to
|
|
||||||
/// the value of the BitCount member for the compression mode specified by Compression.
|
|
||||||
/// </summary>
|
|
||||||
public uint biClrUsed;
|
|
||||||
/// <summary>
|
|
||||||
/// The number of color indexes that are required for displaying the bitmap.
|
|
||||||
/// If this value is zero, all colors are required.
|
|
||||||
/// </summary>
|
|
||||||
public uint biClrImportant;
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region utilities
|
|
||||||
|
|
||||||
const double METER_INCH_RATIO = 39.3700787;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the horizontal dpi of the bitmap.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public float GetXDpi()
|
|
||||||
{
|
{
|
||||||
return (float)Math.Round(biXPelsPerMeter / METER_INCH_RATIO, 0);
|
const double METER_INCH_RATIO = 39.3700787;
|
||||||
}
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the vertical dpi of the bitmap.
|
/// Gets the horizontal dpi of the bitmap.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public float GetYDpi()
|
public float GetXDpi()
|
||||||
{
|
|
||||||
return (float)Math.Round(biYPelsPerMeter / METER_INCH_RATIO, 0);
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the size of the structure.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static uint GetByteSize()
|
|
||||||
{
|
|
||||||
return (uint)Marshal.SizeOf(typeof(BITMAPINFOHEADER));
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// Checks to see if this structure contain valid data.
|
|
||||||
/// It also fills in any missing pieces if possible.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public bool Validate()
|
|
||||||
{
|
|
||||||
if (biHeight != 0 && biWidth != 0 && biBitCount != 0)
|
|
||||||
{
|
|
||||||
if (biSize == 0)
|
|
||||||
{
|
{
|
||||||
biSize = GetByteSize();
|
return (float)Math.Round(biXPelsPerMeter / METER_INCH_RATIO, 0);
|
||||||
}
|
}
|
||||||
if (biClrUsed == 0)
|
/// <summary>
|
||||||
|
/// Gets the vertical dpi of the bitmap.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public float GetYDpi()
|
||||||
{
|
{
|
||||||
switch (biBitCount)
|
return (float)Math.Round(biYPelsPerMeter / METER_INCH_RATIO, 0);
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
biClrUsed = 2;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
biClrUsed = 16;
|
|
||||||
break;
|
|
||||||
case 8:
|
|
||||||
biClrUsed = 256;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (biSizeImage == 0)
|
/// <summary>
|
||||||
|
/// Gets the size of the structure.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static uint GetByteSize()
|
||||||
{
|
{
|
||||||
biSizeImage = (uint)((((
|
return (uint)Marshal.SizeOf<BITMAPINFOHEADER>();
|
||||||
biWidth * biBitCount) + 31) & ~31) >> 3) * (uint)Math.Abs(biHeight);
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Checks to see if this structure contain valid data.
|
||||||
|
/// It also fills in any missing pieces if possible.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public bool Validate()
|
||||||
|
{
|
||||||
|
if (biHeight != 0 && biWidth != 0 && biBitCount != 0)
|
||||||
|
{
|
||||||
|
if (biSize == 0)
|
||||||
|
{
|
||||||
|
biSize = GetByteSize();
|
||||||
|
}
|
||||||
|
if (biClrUsed == 0)
|
||||||
|
{
|
||||||
|
switch (biBitCount)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
biClrUsed = 2;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
biClrUsed = 16;
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
biClrUsed = 256;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (biSizeImage == 0)
|
||||||
|
{
|
||||||
|
biSizeImage = (uint)((((
|
||||||
|
biWidth * biBitCount) + 31) & ~31) >> 3) * (uint)Math.Abs(biHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
/// <summary>
|
||||||
}
|
/// Gets the pointer to scan0 given the header pointer.
|
||||||
return false;
|
/// </summary>
|
||||||
|
/// <param name="headerPtr">The header PTR.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public IntPtr GetScan0(IntPtr headerPtr)
|
||||||
|
{
|
||||||
|
int p = (int)biClrUsed;
|
||||||
|
if ((p == 0) && (biBitCount <= 8))
|
||||||
|
{
|
||||||
|
p = 1 << biBitCount;
|
||||||
|
}
|
||||||
|
p = (p * 4) + (int)biSize + headerPtr.ToInt32();
|
||||||
|
return new IntPtr(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets whether the bitmap is bottom-up or top-down format.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// <c>true</c> if this instance is bottom up image; otherwise, <c>false</c>.
|
||||||
|
/// </value>
|
||||||
|
/// <returns></returns>
|
||||||
|
public bool IsBottomUpImage
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return biHeight > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///// <summary>
|
||||||
|
///// Gets the System.Drawing pixel format of current structure.
|
||||||
|
///// </summary>
|
||||||
|
///// <returns></returns>
|
||||||
|
//public PixelFormat GetDrawingPixelFormat()
|
||||||
|
//{
|
||||||
|
// switch (biBitCount)
|
||||||
|
// {
|
||||||
|
// case 1:
|
||||||
|
// return PixelFormat.Format1bppIndexed;
|
||||||
|
// case 4:
|
||||||
|
// return PixelFormat.Format4bppIndexed;
|
||||||
|
// case 8:
|
||||||
|
// return PixelFormat.Format8bppIndexed;
|
||||||
|
// case 16:
|
||||||
|
// return PixelFormat.Format16bppRgb565;
|
||||||
|
// case 24:
|
||||||
|
// return PixelFormat.Format24bppRgb;
|
||||||
|
// case 32:
|
||||||
|
// return PixelFormat.Format32bppRgb;
|
||||||
|
// case 48:
|
||||||
|
// return PixelFormat.Format48bppRgb;
|
||||||
|
// }
|
||||||
|
// return PixelFormat.DontCare;
|
||||||
|
//}
|
||||||
|
|
||||||
|
///// <summary>
|
||||||
|
///// Gets the color palette that's contained in the header.
|
||||||
|
///// Note not all images will have palette, so check if the return value
|
||||||
|
///// is null before using it.
|
||||||
|
///// </summary>
|
||||||
|
///// <returns></returns>
|
||||||
|
//public ColorPalette? GetDrawingPalette(IntPtr headerPtr)
|
||||||
|
//{
|
||||||
|
// //if (format == PixelFormat.Format8bppIndexed)
|
||||||
|
// //{
|
||||||
|
// // // update color palette to grayscale version
|
||||||
|
// // ColorPalette grayPallet = bitmap.Palette;
|
||||||
|
// // for (int i = 0; i < grayPallet.Entries.Length; i++)
|
||||||
|
// // {
|
||||||
|
// // grayPallet.Entries[i] = Color.FromArgb(i, i, i);
|
||||||
|
// // }
|
||||||
|
// // bitmap.Palette = grayPallet; // this is what makes the gray pallet take effect
|
||||||
|
// //}
|
||||||
|
|
||||||
|
// if (biClrUsed > 0)
|
||||||
|
// {
|
||||||
|
// byte[] data = new byte[biClrUsed * 4];
|
||||||
|
// Marshal.Copy(new IntPtr(headerPtr.ToInt32() + biSize), data, 0, data.Length);
|
||||||
|
// var dummy = new System.Drawing.Bitmap(1, 1, GetDrawingPixelFormat());
|
||||||
|
// ColorPalette pal = dummy.Palette;
|
||||||
|
// dummy.Dispose();
|
||||||
|
// int index = 0;
|
||||||
|
// int setCount = data.Length / 4;
|
||||||
|
// for (int i = 0; i < setCount; i++)
|
||||||
|
// {
|
||||||
|
// index = i * 4;
|
||||||
|
// pal.Entries[i] = Color.FromArgb(data[index + 2], data[index + 1], data[index]);
|
||||||
|
// }
|
||||||
|
// return pal;
|
||||||
|
// }
|
||||||
|
// return null;
|
||||||
|
//}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the stride size of this bitmap.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public int GetStride()
|
||||||
|
{
|
||||||
|
int bitsPerRow = (biBitCount * biWidth);
|
||||||
|
int strideTest = bitsPerRow / 8 + (bitsPerRow % 8 != 0 ? 1 : 0);
|
||||||
|
int overage = strideTest % 4;
|
||||||
|
if (overage > 0)
|
||||||
|
{
|
||||||
|
strideTest += (4 - overage);
|
||||||
|
}
|
||||||
|
return strideTest;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return new StringBuilder().Append("BitmapInfoHeader:")
|
||||||
|
.Append("\r\n\tSize = " + biSize)
|
||||||
|
.Append("\r\n\tWidth = " + biWidth)
|
||||||
|
.Append("\r\n\tHeight = " + biHeight)
|
||||||
|
.Append("\r\n\tPlanes = " + biPlanes)
|
||||||
|
.Append("\r\n\tBitCount = " + biBitCount)
|
||||||
|
.Append("\r\n\tCompression = " + Compression)
|
||||||
|
.Append("\r\n\tSizeImage = " + biSizeImage)
|
||||||
|
.Append("\r\n\tXPixelsPerMeter = " + biXPelsPerMeter)
|
||||||
|
.Append("\r\n\tYPixelsPerMeter = " + biYPelsPerMeter)
|
||||||
|
.Append("\r\n\tColorUsed = " + biClrUsed)
|
||||||
|
.Append("\r\n\tColorImportant = " + biClrImportant).ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the bitmap compression type.
|
||||||
|
/// </summary>
|
||||||
|
public CompressionType Compression { get { return (CompressionType)biCompression; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates the bitmap compression of <seealso cref="BITMAPINFOHEADER"/>.
|
||||||
|
/// </summary>
|
||||||
|
public enum CompressionType : uint
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// An uncompressed format.
|
||||||
|
/// </summary>
|
||||||
|
BI_RGB = 0,
|
||||||
|
/// <summary>
|
||||||
|
/// A run-length encoded (RLE) format for bitmaps with 8 bpp. The compression format is a 2-byte format consisting of a count byte followed by a byte containing a color index. For more information, see Bitmap Compression.
|
||||||
|
/// </summary>
|
||||||
|
BI_RLE8 = 1,
|
||||||
|
/// <summary>
|
||||||
|
/// An RLE, format for bitmaps with 4 bpp. The compression format is a 2-byte format consisting of a count byte followed by two word-length color indexes. For more information, see Bitmap Compression.
|
||||||
|
/// </summary>
|
||||||
|
BI_RLE4 = 2,
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies that the bitmap is not compressed and that the color table consists of three DWORD color masks that specify the red, green, and blue components of each pixel.
|
||||||
|
/// This is valid when used with 16- and 32-bpp bitmaps.
|
||||||
|
/// </summary>
|
||||||
|
BI_BITFIELDS = 3,
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates that the image is a JPEG image.
|
||||||
|
/// </summary>
|
||||||
|
BI_JPEG = 4,
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates that the image is a PNG image.
|
||||||
|
/// </summary>
|
||||||
|
BI_PNG = 5
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
//[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||||
/// Gets the pointer to scan0 given the header pointer.
|
//struct BITMAPFILEHEADER
|
||||||
/// </summary>
|
|
||||||
/// <param name="headerPtr">The header PTR.</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public IntPtr GetScan0(IntPtr headerPtr)
|
|
||||||
{
|
|
||||||
int p = (int)biClrUsed;
|
|
||||||
if ((p == 0) && (biBitCount <= 8))
|
|
||||||
{
|
|
||||||
p = 1 << biBitCount;
|
|
||||||
}
|
|
||||||
p = (p * 4) + (int)biSize + headerPtr.ToInt32();
|
|
||||||
return new IntPtr(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets whether the bitmap is bottom-up or top-down format.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>
|
|
||||||
/// <c>true</c> if this instance is bottom up image; otherwise, <c>false</c>.
|
|
||||||
/// </value>
|
|
||||||
/// <returns></returns>
|
|
||||||
public bool IsBottomUpImage
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return biHeight > 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
///// <summary>
|
|
||||||
///// Gets the System.Drawing pixel format of current structure.
|
|
||||||
///// </summary>
|
|
||||||
///// <returns></returns>
|
|
||||||
//public PixelFormat GetDrawingPixelFormat()
|
|
||||||
//{
|
//{
|
||||||
// switch (biBitCount)
|
// public ushort bfType;
|
||||||
// {
|
// public uint bfSize;
|
||||||
// case 1:
|
// public ushort bfReserved1;
|
||||||
// return PixelFormat.Format1bppIndexed;
|
// public ushort bfReserved2;
|
||||||
// case 4:
|
// public uint bfOffBits;
|
||||||
// return PixelFormat.Format4bppIndexed;
|
|
||||||
// case 8:
|
|
||||||
// return PixelFormat.Format8bppIndexed;
|
|
||||||
// case 16:
|
|
||||||
// return PixelFormat.Format16bppRgb565;
|
|
||||||
// case 24:
|
|
||||||
// return PixelFormat.Format24bppRgb;
|
|
||||||
// case 32:
|
|
||||||
// return PixelFormat.Format32bppRgb;
|
|
||||||
// case 48:
|
|
||||||
// return PixelFormat.Format48bppRgb;
|
|
||||||
// }
|
|
||||||
// return PixelFormat.DontCare;
|
|
||||||
//}
|
//}
|
||||||
|
|
||||||
///// <summary>
|
|
||||||
///// Gets the color palette that's contained in the header.
|
|
||||||
///// Note not all images will have palette, so check if the return value
|
|
||||||
///// is null before using it.
|
|
||||||
///// </summary>
|
|
||||||
///// <returns></returns>
|
|
||||||
//public ColorPalette? GetDrawingPalette(IntPtr headerPtr)
|
|
||||||
//{
|
|
||||||
// //if (format == PixelFormat.Format8bppIndexed)
|
|
||||||
// //{
|
|
||||||
// // // update color palette to grayscale version
|
|
||||||
// // ColorPalette grayPallet = bitmap.Palette;
|
|
||||||
// // for (int i = 0; i < grayPallet.Entries.Length; i++)
|
|
||||||
// // {
|
|
||||||
// // grayPallet.Entries[i] = Color.FromArgb(i, i, i);
|
|
||||||
// // }
|
|
||||||
// // bitmap.Palette = grayPallet; // this is what makes the gray pallet take effect
|
|
||||||
// //}
|
|
||||||
|
|
||||||
// if (biClrUsed > 0)
|
|
||||||
// {
|
|
||||||
// byte[] data = new byte[biClrUsed * 4];
|
|
||||||
// Marshal.Copy(new IntPtr(headerPtr.ToInt32() + biSize), data, 0, data.Length);
|
|
||||||
// var dummy = new System.Drawing.Bitmap(1, 1, GetDrawingPixelFormat());
|
|
||||||
// ColorPalette pal = dummy.Palette;
|
|
||||||
// dummy.Dispose();
|
|
||||||
// int index = 0;
|
|
||||||
// int setCount = data.Length / 4;
|
|
||||||
// for (int i = 0; i < setCount; i++)
|
|
||||||
// {
|
|
||||||
// index = i * 4;
|
|
||||||
// pal.Entries[i] = Color.FromArgb(data[index + 2], data[index + 1], data[index]);
|
|
||||||
// }
|
|
||||||
// return pal;
|
|
||||||
// }
|
|
||||||
// return null;
|
|
||||||
//}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the stride size of this bitmap.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public int GetStride()
|
|
||||||
{
|
|
||||||
int bitsPerRow = (biBitCount * biWidth);
|
|
||||||
int strideTest = bitsPerRow / 8 + (bitsPerRow % 8 != 0 ? 1 : 0);
|
|
||||||
int overage = strideTest % 4;
|
|
||||||
if (overage > 0)
|
|
||||||
{
|
|
||||||
strideTest += (4 - overage);
|
|
||||||
}
|
|
||||||
return strideTest;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a <see cref="System.String" /> that represents this instance.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>
|
|
||||||
/// A <see cref="System.String" /> that represents this instance.
|
|
||||||
/// </returns>
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return new StringBuilder().Append("BitmapInfoHeader:")
|
|
||||||
.Append("\r\n\tSize = " + biSize)
|
|
||||||
.Append("\r\n\tWidth = " + biWidth)
|
|
||||||
.Append("\r\n\tHeight = " + biHeight)
|
|
||||||
.Append("\r\n\tPlanes = " + biPlanes)
|
|
||||||
.Append("\r\n\tBitCount = " + biBitCount)
|
|
||||||
.Append("\r\n\tCompression = " + biCompression)
|
|
||||||
.Append("\r\n\tSizeImage = " + biSizeImage)
|
|
||||||
.Append("\r\n\tXPixelsPerMeter = " + biXPelsPerMeter)
|
|
||||||
.Append("\r\n\tYPixelsPerMeter = " + biYPelsPerMeter)
|
|
||||||
.Append("\r\n\tColorUsed = " + biClrUsed)
|
|
||||||
.Append("\r\n\tColorImportant = " + biClrImportant).ToString();
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Indicates the bitmap compression of <seealso cref="BITMAPINFOHEADER"/>.
|
|
||||||
/// </summary>
|
|
||||||
public enum CompressionType : uint
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// An uncompressed format.
|
|
||||||
/// </summary>
|
|
||||||
BI_RGB = 0,
|
|
||||||
/// <summary>
|
|
||||||
/// A run-length encoded (RLE) format for bitmaps with 8 bpp. The compression format is a 2-byte format consisting of a count byte followed by a byte containing a color index. For more information, see Bitmap Compression.
|
|
||||||
/// </summary>
|
|
||||||
BI_RLE8 = 1,
|
|
||||||
/// <summary>
|
|
||||||
/// An RLE, format for bitmaps with 4 bpp. The compression format is a 2-byte format consisting of a count byte followed by two word-length color indexes. For more information, see Bitmap Compression.
|
|
||||||
/// </summary>
|
|
||||||
BI_RLE4 = 2,
|
|
||||||
/// <summary>
|
|
||||||
/// Specifies that the bitmap is not compressed and that the color table consists of three DWORD color masks that specify the red, green, and blue components of each pixel.
|
|
||||||
/// This is valid when used with 16- and 32-bpp bitmaps.
|
|
||||||
/// </summary>
|
|
||||||
BI_BITFIELDS = 3,
|
|
||||||
/// <summary>
|
|
||||||
/// Indicates that the image is a JPEG image.
|
|
||||||
/// </summary>
|
|
||||||
BI_JPEG = 4,
|
|
||||||
/// <summary>
|
|
||||||
/// Indicates that the image is a PNG image.
|
|
||||||
/// </summary>
|
|
||||||
BI_PNG = 5
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
|
||||||
struct BITMAPFILEHEADER
|
|
||||||
{
|
|
||||||
public ushort bfType;
|
|
||||||
public uint bfSize;
|
|
||||||
public ushort bfReserved1;
|
|
||||||
public ushort bfReserved2;
|
|
||||||
public uint bfOffBits;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+129
-128
@@ -1,145 +1,146 @@
|
|||||||
using NTwain.Data;
|
using NTwain.Data;
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using Windows.Win32.Graphics.Gdi;
|
||||||
|
|
||||||
namespace NTwain.Native
|
namespace NTwain.Native
|
||||||
{
|
{
|
||||||
static class ImageTools
|
static class ImageTools
|
||||||
{
|
|
||||||
// this is modified from twain cs sample
|
|
||||||
// http://sourceforge.net/projects/twainforcsharp/?source=typ_redirect
|
|
||||||
|
|
||||||
public static bool IsDib(IntPtr data)
|
|
||||||
{
|
{
|
||||||
// a quick check not guaranteed correct,
|
// this is modified from twain cs sample
|
||||||
// compare first 2 bytes to size of struct (which is also the first field)
|
// http://sourceforge.net/projects/twainforcsharp/?source=typ_redirect
|
||||||
var test = Marshal.ReadInt16(data);
|
|
||||||
// should be 40
|
|
||||||
return test == BITMAPINFOHEADER.GetByteSize();
|
|
||||||
}
|
|
||||||
public static bool IsTiff(IntPtr data)
|
|
||||||
{
|
|
||||||
var test = Marshal.ReadInt16(data);
|
|
||||||
// should be II
|
|
||||||
return test == 0x4949;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static unsafe BufferedData? GetBitmapData(IntPtr data)
|
public static bool IsDib(IntPtr data)
|
||||||
{
|
|
||||||
var infoHeader = Marshal.PtrToStructure<BITMAPINFOHEADER>(data);
|
|
||||||
if (infoHeader.Validate())
|
|
||||||
{
|
|
||||||
var fileHeaderSize = Marshal.SizeOf(typeof(BITMAPFILEHEADER));
|
|
||||||
|
|
||||||
var fileHeader = new BITMAPFILEHEADER
|
|
||||||
{
|
{
|
||||||
bfType = 0x4D42, // "BM"
|
// a quick check not guaranteed correct,
|
||||||
bfOffBits = (uint)fileHeaderSize +
|
// compare first 2 bytes to size of struct (which is also the first field)
|
||||||
infoHeader.biSize +
|
var test = Marshal.ReadInt16(data);
|
||||||
(infoHeader.biClrUsed * 4)
|
// should be 40
|
||||||
};
|
return test == BITMAPINFOHEADER.GetByteSize();
|
||||||
fileHeader.bfSize = fileHeader.bfOffBits + infoHeader.biSizeImage;
|
}
|
||||||
|
public static bool IsTiff(IntPtr data)
|
||||||
var dataCopy = BufferedData.MemPool.Rent((int)fileHeader.bfSize); // new byte[fileHeader.bfSize];
|
|
||||||
|
|
||||||
// TODO: run benchmark on which one is faster
|
|
||||||
|
|
||||||
// write file header
|
|
||||||
//IntPtr tempPtr = Marshal.AllocHGlobal(fileHeaderSize);
|
|
||||||
//Marshal.StructureToPtr(fileHeader, tempPtr, true);
|
|
||||||
//Marshal.Copy(tempPtr, dataCopy, 0, fileHeaderSize);
|
|
||||||
//Marshal.FreeHGlobal(tempPtr);
|
|
||||||
|
|
||||||
// would this be faster?
|
|
||||||
fixed (byte* p = dataCopy)
|
|
||||||
{
|
{
|
||||||
Marshal.StructureToPtr(fileHeader, (IntPtr)p, false);
|
var test = Marshal.ReadInt16(data);
|
||||||
|
// should be II
|
||||||
|
return test == 0x4949;
|
||||||
}
|
}
|
||||||
|
|
||||||
// write image
|
public static unsafe BufferedData? GetBitmapData(IntPtr data)
|
||||||
Marshal.Copy(data, dataCopy, fileHeaderSize, (int)fileHeader.bfSize - fileHeaderSize);
|
|
||||||
return new BufferedData(dataCopy, (int)fileHeader.bfSize, true);
|
|
||||||
}
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static BufferedData? GetTiffData(IntPtr data)
|
|
||||||
{
|
|
||||||
// Find the size of the image so we can turn it into a memory stream...
|
|
||||||
var headerSize = Marshal.SizeOf(typeof(TIFFHEADER));
|
|
||||||
var tagSize = Marshal.SizeOf(typeof(TIFFTAG));
|
|
||||||
var tiffSize = 0;
|
|
||||||
var tagPtr = data.ToInt64() + headerSize;
|
|
||||||
for (int i = 0; i < 999; i++)
|
|
||||||
{
|
|
||||||
tagPtr += (tagSize * i);
|
|
||||||
var tag = Marshal.PtrToStructure<TIFFTAG>((IntPtr)tagPtr);
|
|
||||||
|
|
||||||
switch (tag.u16Tag)
|
|
||||||
{
|
{
|
||||||
case 273: // StripOffsets...
|
var infoHeader = Marshal.PtrToStructure<BITMAPINFOHEADER>(data);
|
||||||
case 279: // StripByteCounts...
|
if (infoHeader.Validate())
|
||||||
tiffSize += (int)tag.u32Value;
|
{
|
||||||
break;
|
var fileHeaderSize = Marshal.SizeOf<BITMAPFILEHEADER>();
|
||||||
|
|
||||||
|
var fileHeader = new BITMAPFILEHEADER
|
||||||
|
{
|
||||||
|
bfType = 0x4D42, // "BM"
|
||||||
|
bfOffBits = (uint)fileHeaderSize +
|
||||||
|
infoHeader.biSize +
|
||||||
|
(infoHeader.biClrUsed * 4)
|
||||||
|
};
|
||||||
|
fileHeader.bfSize = fileHeader.bfOffBits + infoHeader.biSizeImage;
|
||||||
|
|
||||||
|
var dataCopy = BufferedData.MemPool.Rent((int)fileHeader.bfSize); // new byte[fileHeader.bfSize];
|
||||||
|
|
||||||
|
// TODO: run benchmark on which one is faster
|
||||||
|
|
||||||
|
// write file header
|
||||||
|
//IntPtr tempPtr = Marshal.AllocHGlobal(fileHeaderSize);
|
||||||
|
//Marshal.StructureToPtr(fileHeader, tempPtr, true);
|
||||||
|
//Marshal.Copy(tempPtr, dataCopy, 0, fileHeaderSize);
|
||||||
|
//Marshal.FreeHGlobal(tempPtr);
|
||||||
|
|
||||||
|
// would this be faster?
|
||||||
|
fixed (byte* p = dataCopy)
|
||||||
|
{
|
||||||
|
Marshal.StructureToPtr(fileHeader, (IntPtr)p, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// write image
|
||||||
|
Marshal.Copy(data, dataCopy, fileHeaderSize, (int)fileHeader.bfSize - fileHeaderSize);
|
||||||
|
return new BufferedData(dataCopy, (int)fileHeader.bfSize, true);
|
||||||
|
}
|
||||||
|
return default;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (tiffSize > 0)
|
public static BufferedData? GetTiffData(IntPtr data)
|
||||||
{
|
{
|
||||||
var dataCopy = BufferedData.MemPool.Rent(tiffSize);// new byte[tiffSize];
|
// Find the size of the image so we can turn it into a memory stream...
|
||||||
Marshal.Copy(data, dataCopy, 0, tiffSize);
|
var headerSize = Marshal.SizeOf<TIFFHEADER>();
|
||||||
return new BufferedData(dataCopy, tiffSize, true);
|
var tagSize = Marshal.SizeOf<TIFFTAG>();
|
||||||
}
|
var tiffSize = 0;
|
||||||
return default;
|
var tagPtr = data.ToInt64() + headerSize;
|
||||||
|
for (int i = 0; i < 999; i++)
|
||||||
|
{
|
||||||
|
tagPtr += (tagSize * i);
|
||||||
|
var tag = Marshal.PtrToStructure<TIFFTAG>((IntPtr)tagPtr);
|
||||||
|
|
||||||
|
switch (tag.u16Tag)
|
||||||
|
{
|
||||||
|
case 273: // StripOffsets...
|
||||||
|
case 279: // StripByteCounts...
|
||||||
|
tiffSize += (int)tag.u32Value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tiffSize > 0)
|
||||||
|
{
|
||||||
|
var dataCopy = BufferedData.MemPool.Rent(tiffSize);// new byte[tiffSize];
|
||||||
|
Marshal.Copy(data, dataCopy, 0, tiffSize);
|
||||||
|
return new BufferedData(dataCopy, tiffSize, true);
|
||||||
|
}
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
|
||||||
|
//internal static Bitmap ReadBitmapImage(IntPtr data)
|
||||||
|
//{
|
||||||
|
// Bitmap finalImg = null;
|
||||||
|
// Bitmap tempImg = null;
|
||||||
|
// try
|
||||||
|
// {
|
||||||
|
// var header = (BITMAPINFOHEADER)Marshal.PtrToStructure(data, typeof(BITMAPINFOHEADER));
|
||||||
|
|
||||||
|
// if (header.Validate())
|
||||||
|
// {
|
||||||
|
// PixelFormat format = header.GetDrawingPixelFormat();
|
||||||
|
// tempImg = new Bitmap(header.biWidth, Math.Abs(header.biHeight), header.GetStride(), format, header.GetScan0(data));
|
||||||
|
// ColorPalette pal = header.GetDrawingPalette(data);
|
||||||
|
// if (pal != null)
|
||||||
|
// {
|
||||||
|
// tempImg.Palette = pal;
|
||||||
|
// }
|
||||||
|
// float xdpi = header.GetXDpi();
|
||||||
|
// float ydpi = header.GetYDpi();
|
||||||
|
// if (xdpi != 0 && ydpi == 0)
|
||||||
|
// {
|
||||||
|
// ydpi = xdpi;
|
||||||
|
// }
|
||||||
|
// else if (ydpi != 0 && xdpi == 0)
|
||||||
|
// {
|
||||||
|
// xdpi = ydpi;
|
||||||
|
// }
|
||||||
|
// if (xdpi != 0)
|
||||||
|
// {
|
||||||
|
// tempImg.SetResolution(xdpi, ydpi);
|
||||||
|
// }
|
||||||
|
// if (header.IsBottomUpImage)
|
||||||
|
// {
|
||||||
|
// tempImg.RotateFlip(RotateFlipType.RotateNoneFlipY);
|
||||||
|
// }
|
||||||
|
// finalImg = tempImg;
|
||||||
|
// tempImg = null;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// finally
|
||||||
|
// {
|
||||||
|
// if (tempImg != null)
|
||||||
|
// {
|
||||||
|
// tempImg.Dispose();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return finalImg;
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
//internal static Bitmap ReadBitmapImage(IntPtr data)
|
|
||||||
//{
|
|
||||||
// Bitmap finalImg = null;
|
|
||||||
// Bitmap tempImg = null;
|
|
||||||
// try
|
|
||||||
// {
|
|
||||||
// var header = (BITMAPINFOHEADER)Marshal.PtrToStructure(data, typeof(BITMAPINFOHEADER));
|
|
||||||
|
|
||||||
// if (header.Validate())
|
|
||||||
// {
|
|
||||||
// PixelFormat format = header.GetDrawingPixelFormat();
|
|
||||||
// tempImg = new Bitmap(header.biWidth, Math.Abs(header.biHeight), header.GetStride(), format, header.GetScan0(data));
|
|
||||||
// ColorPalette pal = header.GetDrawingPalette(data);
|
|
||||||
// if (pal != null)
|
|
||||||
// {
|
|
||||||
// tempImg.Palette = pal;
|
|
||||||
// }
|
|
||||||
// float xdpi = header.GetXDpi();
|
|
||||||
// float ydpi = header.GetYDpi();
|
|
||||||
// if (xdpi != 0 && ydpi == 0)
|
|
||||||
// {
|
|
||||||
// ydpi = xdpi;
|
|
||||||
// }
|
|
||||||
// else if (ydpi != 0 && xdpi == 0)
|
|
||||||
// {
|
|
||||||
// xdpi = ydpi;
|
|
||||||
// }
|
|
||||||
// if (xdpi != 0)
|
|
||||||
// {
|
|
||||||
// tempImg.SetResolution(xdpi, ydpi);
|
|
||||||
// }
|
|
||||||
// if (header.IsBottomUpImage)
|
|
||||||
// {
|
|
||||||
// tempImg.RotateFlip(RotateFlipType.RotateNoneFlipY);
|
|
||||||
// }
|
|
||||||
// finalImg = tempImg;
|
|
||||||
// tempImg = null;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// finally
|
|
||||||
// {
|
|
||||||
// if (tempImg != null)
|
|
||||||
// {
|
|
||||||
// tempImg.Dispose();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// return finalImg;
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
using System;
|
//using System;
|
||||||
using System.Runtime.InteropServices;
|
//using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace NTwain.Native
|
//namespace NTwain.Native
|
||||||
{
|
//{
|
||||||
/// <summary>
|
// /// <summary>
|
||||||
/// The MSG structure in Windows for TWAIN use.
|
// /// The MSG structure in Windows for TWAIN use.
|
||||||
/// </summary>
|
// /// </summary>
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
// [StructLayout(LayoutKind.Sequential)]
|
||||||
struct WIN_MESSAGE
|
// struct WIN_MESSAGE
|
||||||
{
|
// {
|
||||||
public IntPtr hwnd;
|
// public IntPtr hwnd;
|
||||||
public uint message;
|
// public uint message;
|
||||||
public IntPtr wParam;
|
// public IntPtr wParam;
|
||||||
public IntPtr lParam;
|
// public IntPtr lParam;
|
||||||
uint _time;
|
// uint _time;
|
||||||
int _x;
|
// int _x;
|
||||||
int _y;
|
// int _y;
|
||||||
uint lprivate;
|
// uint lprivate;
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
|||||||
@@ -1,97 +1,97 @@
|
|||||||
using System;
|
//using System;
|
||||||
using System.Runtime.InteropServices;
|
//using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace NTwain.Native
|
//namespace NTwain.Native
|
||||||
{
|
//{
|
||||||
/// <summary>
|
// /// <summary>
|
||||||
/// Native methods for windows.
|
// /// Native methods for windows.
|
||||||
/// </summary>
|
// /// </summary>
|
||||||
static partial class WinNativeMethods
|
// static partial class WinNativeMethods
|
||||||
{
|
// {
|
||||||
#if NET7_0_OR_GREATER
|
//#if NET7_0_OR_GREATER
|
||||||
[LibraryImport("kernel32", SetLastError = true)]
|
// [LibraryImport("kernel32", SetLastError = true)]
|
||||||
public static partial IntPtr GlobalAlloc(AllocFlag uFlags, UIntPtr dwBytes);
|
// public static partial IntPtr GlobalAlloc(AllocFlag uFlags, UIntPtr dwBytes);
|
||||||
|
|
||||||
[LibraryImport("kernel32", SetLastError = true)]
|
// [LibraryImport("kernel32", SetLastError = true)]
|
||||||
public static partial IntPtr GlobalFree(IntPtr hMem);
|
// public static partial IntPtr GlobalFree(IntPtr hMem);
|
||||||
|
|
||||||
[LibraryImport("kernel32", SetLastError = true)]
|
// [LibraryImport("kernel32", SetLastError = true)]
|
||||||
public static partial IntPtr GlobalLock(IntPtr handle);
|
// public static partial IntPtr GlobalLock(IntPtr handle);
|
||||||
|
|
||||||
[LibraryImport("kernel32", SetLastError = true)]
|
// [LibraryImport("kernel32", SetLastError = true)]
|
||||||
[return: MarshalAs(UnmanagedType.Bool)]
|
// [return: MarshalAs(UnmanagedType.Bool)]
|
||||||
public static partial bool GlobalUnlock(IntPtr handle);
|
// public static partial bool GlobalUnlock(IntPtr handle);
|
||||||
#else
|
//#else
|
||||||
[DllImport("kernel32", SetLastError = true)]
|
// [DllImport("kernel32", SetLastError = true)]
|
||||||
public static extern IntPtr GlobalAlloc(AllocFlag uFlags, UIntPtr dwBytes);
|
// public static extern IntPtr GlobalAlloc(AllocFlag uFlags, UIntPtr dwBytes);
|
||||||
|
|
||||||
[DllImport("kernel32", SetLastError = true)]
|
// [DllImport("kernel32", SetLastError = true)]
|
||||||
public static extern IntPtr GlobalFree(IntPtr hMem);
|
// public static extern IntPtr GlobalFree(IntPtr hMem);
|
||||||
|
|
||||||
[DllImport("kernel32", SetLastError = true)]
|
// [DllImport("kernel32", SetLastError = true)]
|
||||||
public static extern IntPtr GlobalLock(IntPtr handle);
|
// public static extern IntPtr GlobalLock(IntPtr handle);
|
||||||
|
|
||||||
[DllImport("kernel32", SetLastError = true)]
|
// [DllImport("kernel32", SetLastError = true)]
|
||||||
[return: MarshalAs(UnmanagedType.Bool)]
|
// [return: MarshalAs(UnmanagedType.Bool)]
|
||||||
public static extern bool GlobalUnlock(IntPtr handle);
|
// public static extern bool GlobalUnlock(IntPtr handle);
|
||||||
#endif
|
//#endif
|
||||||
|
|
||||||
[Flags]
|
|
||||||
public enum AllocFlag : uint
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Allocates fixed memory. The return value is a pointer.
|
|
||||||
/// </summary>
|
|
||||||
GMEM_FIXED = 0,
|
|
||||||
/// <summary>
|
|
||||||
/// Allocates movable memory. Memory blocks are never moved in physical memory, but they can be moved within the default heap.
|
|
||||||
/// The return value is a handle to the memory object. To translate the handle into a pointer, use the GlobalLock function.
|
|
||||||
/// </summary>
|
|
||||||
GMEM_MOVEABLE = 2,
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes memory contents to zero.
|
|
||||||
/// </summary>
|
|
||||||
GMEM_ZEROINIT = 0x40,
|
|
||||||
GPTR = GMEM_FIXED | GMEM_ZEROINIT,
|
|
||||||
GHND = GMEM_MOVEABLE | GMEM_ZEROINIT
|
|
||||||
}
|
|
||||||
|
|
||||||
// [Flags]
|
// [Flags]
|
||||||
// public enum PEEK_MESSAGE_REMOVE_TYPE : uint
|
// public enum AllocFlag : uint
|
||||||
// {
|
// {
|
||||||
// PM_NOREMOVE = 0x00000000,
|
// /// <summary>
|
||||||
// PM_REMOVE = 0x00000001,
|
// /// Allocates fixed memory. The return value is a pointer.
|
||||||
// PM_NOYIELD = 0x00000002,
|
// /// </summary>
|
||||||
// PM_QS_INPUT = 0x04070000,
|
// GMEM_FIXED = 0,
|
||||||
// PM_QS_POSTMESSAGE = 0x00980000,
|
// /// <summary>
|
||||||
// PM_QS_PAINT = 0x00200000,
|
// /// Allocates movable memory. Memory blocks are never moved in physical memory, but they can be moved within the default heap.
|
||||||
// PM_QS_SENDMESSAGE = 0x00400000,
|
// /// The return value is a handle to the memory object. To translate the handle into a pointer, use the GlobalLock function.
|
||||||
|
// /// </summary>
|
||||||
|
// GMEM_MOVEABLE = 2,
|
||||||
|
// /// <summary>
|
||||||
|
// /// Initializes memory contents to zero.
|
||||||
|
// /// </summary>
|
||||||
|
// GMEM_ZEROINIT = 0x40,
|
||||||
|
// GPTR = GMEM_FIXED | GMEM_ZEROINIT,
|
||||||
|
// GHND = GMEM_MOVEABLE | GMEM_ZEROINIT
|
||||||
// }
|
// }
|
||||||
|
|
||||||
//#if NET7_0_OR_GREATER
|
//// [Flags]
|
||||||
// [LibraryImport("USER32.dll")]
|
//// public enum PEEK_MESSAGE_REMOVE_TYPE : uint
|
||||||
// public static partial int PeekMessageW(ref WIN_MESSAGE lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax, PEEK_MESSAGE_REMOVE_TYPE wRemoveMsg);
|
//// {
|
||||||
|
//// PM_NOREMOVE = 0x00000000,
|
||||||
|
//// PM_REMOVE = 0x00000001,
|
||||||
|
//// PM_NOYIELD = 0x00000002,
|
||||||
|
//// PM_QS_INPUT = 0x04070000,
|
||||||
|
//// PM_QS_POSTMESSAGE = 0x00980000,
|
||||||
|
//// PM_QS_PAINT = 0x00200000,
|
||||||
|
//// PM_QS_SENDMESSAGE = 0x00400000,
|
||||||
|
//// }
|
||||||
|
|
||||||
// [LibraryImport("USER32.dll", SetLastError = true)]
|
////#if NET7_0_OR_GREATER
|
||||||
// public static partial int GetMessageW(ref WIN_MESSAGE lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax);
|
//// [LibraryImport("USER32.dll")]
|
||||||
|
//// public static partial int PeekMessageW(ref WIN_MESSAGE lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax, PEEK_MESSAGE_REMOVE_TYPE wRemoveMsg);
|
||||||
|
|
||||||
// [LibraryImport("USER32.dll")]
|
//// [LibraryImport("USER32.dll", SetLastError = true)]
|
||||||
// public static partial int TranslateMessage(ref WIN_MESSAGE lpMsg);
|
//// public static partial int GetMessageW(ref WIN_MESSAGE lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax);
|
||||||
|
|
||||||
// [LibraryImport("USER32.dll")]
|
//// [LibraryImport("USER32.dll")]
|
||||||
// public static partial nint DispatchMessageW(ref WIN_MESSAGE lpMsg);
|
//// public static partial int TranslateMessage(ref WIN_MESSAGE lpMsg);
|
||||||
//#else
|
|
||||||
// [DllImport("USER32.dll")]
|
|
||||||
// public static extern int PeekMessageW(ref WIN_MESSAGE lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax, PEEK_MESSAGE_REMOVE_TYPE wRemoveMsg);
|
|
||||||
|
|
||||||
// [DllImport("USER32.dll", SetLastError = true)]
|
//// [LibraryImport("USER32.dll")]
|
||||||
// public static extern int GetMessageW(ref WIN_MESSAGE lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax);
|
//// public static partial nint DispatchMessageW(ref WIN_MESSAGE lpMsg);
|
||||||
|
////#else
|
||||||
|
//// [DllImport("USER32.dll")]
|
||||||
|
//// public static extern int PeekMessageW(ref WIN_MESSAGE lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax, PEEK_MESSAGE_REMOVE_TYPE wRemoveMsg);
|
||||||
|
|
||||||
// [DllImport("USER32.dll")]
|
//// [DllImport("USER32.dll", SetLastError = true)]
|
||||||
// public static extern int TranslateMessage(ref WIN_MESSAGE lpMsg);
|
//// public static extern int GetMessageW(ref WIN_MESSAGE lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax);
|
||||||
|
|
||||||
// [DllImport("USER32.dll")]
|
//// [DllImport("USER32.dll")]
|
||||||
// public static extern nint DispatchMessageW(ref WIN_MESSAGE lpMsg);
|
//// public static extern int TranslateMessage(ref WIN_MESSAGE lpMsg);
|
||||||
//#endif
|
|
||||||
}
|
//// [DllImport("USER32.dll")]
|
||||||
}
|
//// public static extern nint DispatchMessageW(ref WIN_MESSAGE lpMsg);
|
||||||
|
////#endif
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://aka.ms/CsWin32.schema.json",
|
||||||
|
"allowMarshaling": false
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
MSG
|
||||||
|
GlobalAlloc
|
||||||
|
GlobalFree
|
||||||
|
GlobalLock
|
||||||
|
GlobalUnlock
|
||||||
|
BITMAPINFOHEADER
|
||||||
|
BITMAPINFO
|
||||||
|
BITMAPFILEHEADER
|
||||||
@@ -1,114 +1,131 @@
|
|||||||
using NTwain.Data;
|
using NTwain.Data;
|
||||||
using NTwain.Native;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using Windows.Win32;
|
||||||
|
using Windows.Win32.Foundation;
|
||||||
|
using Windows.Win32.System.Memory;
|
||||||
|
|
||||||
namespace NTwain
|
namespace NTwain
|
||||||
{
|
{
|
||||||
// this file contains memory methods
|
// this file contains memory methods
|
||||||
|
|
||||||
partial class TwainAppSession : IMemoryManager
|
partial class TwainAppSession : IMemoryManager
|
||||||
{
|
|
||||||
TW_ENTRYPOINT_DELEGATES _entryPoint;
|
|
||||||
|
|
||||||
public IntPtr Alloc(uint size)
|
|
||||||
{
|
{
|
||||||
if (_entryPoint.DSM_MemAllocate != null)
|
TW_ENTRYPOINT_DELEGATES _entryPoint;
|
||||||
{
|
|
||||||
return _entryPoint.DSM_MemAllocate(size);
|
public IntPtr Alloc(uint size)
|
||||||
}
|
{
|
||||||
else if (TWPlatform.IsWindows)
|
if (_entryPoint.DSM_MemAllocate != null)
|
||||||
{
|
{
|
||||||
return WinNativeMethods.GlobalAlloc(WinNativeMethods.AllocFlag.GHND, (UIntPtr)size);
|
return _entryPoint.DSM_MemAllocate(size);
|
||||||
}
|
}
|
||||||
else if (TWPlatform.IsLinux)
|
else if (TWPlatform.IsWindows)
|
||||||
{
|
{
|
||||||
return Marshal.AllocHGlobal((int)size);
|
#pragma warning disable CA1416 // Validate platform compatibility
|
||||||
}
|
return PInvoke.GlobalAlloc(GLOBAL_ALLOC_FLAGS.GHND, size);
|
||||||
else if (TWPlatform.IsMacOSX)
|
#pragma warning restore CA1416 // Validate platform compatibility
|
||||||
{
|
//return WinNativeMethods.GlobalAlloc(WinNativeMethods.AllocFlag.GHND, (UIntPtr)size);
|
||||||
return Marshal.AllocHGlobal((int)size);
|
}
|
||||||
}
|
else if (TWPlatform.IsLinux)
|
||||||
else
|
{
|
||||||
{
|
return Marshal.AllocHGlobal((int)size);
|
||||||
throw new PlatformNotSupportedException();
|
}
|
||||||
}
|
else if (TWPlatform.IsMacOSX)
|
||||||
|
{
|
||||||
|
return Marshal.AllocHGlobal((int)size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new PlatformNotSupportedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Free(IntPtr handle)
|
||||||
|
{
|
||||||
|
if (handle == IntPtr.Zero) return;
|
||||||
|
|
||||||
|
if (_entryPoint.DSM_MemFree != null)
|
||||||
|
{
|
||||||
|
_entryPoint.DSM_MemFree(handle);
|
||||||
|
}
|
||||||
|
else if (TWPlatform.IsWindows)
|
||||||
|
{
|
||||||
|
#pragma warning disable CA1416 // Validate platform compatibility
|
||||||
|
PInvoke.GlobalFree((HGLOBAL)handle);
|
||||||
|
#pragma warning restore CA1416 // Validate platform compatibility
|
||||||
|
//WinNativeMethods.GlobalFree(handle);
|
||||||
|
}
|
||||||
|
else if (TWPlatform.IsLinux)
|
||||||
|
{
|
||||||
|
Marshal.FreeHGlobal(handle);
|
||||||
|
}
|
||||||
|
else if (TWPlatform.IsMacOSX)
|
||||||
|
{
|
||||||
|
Marshal.FreeHGlobal(handle);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new PlatformNotSupportedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IntPtr Lock(IntPtr handle)
|
||||||
|
{
|
||||||
|
if (handle == IntPtr.Zero) return IntPtr.Zero;
|
||||||
|
|
||||||
|
if (_entryPoint.DSM_MemLock != null)
|
||||||
|
{
|
||||||
|
return _entryPoint.DSM_MemLock(handle);
|
||||||
|
}
|
||||||
|
else if (TWPlatform.IsWindows)
|
||||||
|
{
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
#pragma warning disable CA1416 // Validate platform compatibility
|
||||||
|
return (IntPtr)PInvoke.GlobalLock((HGLOBAL)handle);
|
||||||
|
#pragma warning restore CA1416 // Validate platform compatibility
|
||||||
|
}
|
||||||
|
//return WinNativeMethods.GlobalLock(handle);
|
||||||
|
}
|
||||||
|
else if (TWPlatform.IsLinux)
|
||||||
|
{
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
else if (TWPlatform.IsMacOSX)
|
||||||
|
{
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new PlatformNotSupportedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Unlock(IntPtr handle)
|
||||||
|
{
|
||||||
|
if (handle == IntPtr.Zero) return;
|
||||||
|
|
||||||
|
if (_entryPoint.DSM_MemUnlock != null)
|
||||||
|
{
|
||||||
|
_entryPoint.DSM_MemUnlock(handle);
|
||||||
|
}
|
||||||
|
else if (TWPlatform.IsWindows)
|
||||||
|
{
|
||||||
|
#pragma warning disable CA1416 // Validate platform compatibility
|
||||||
|
PInvoke.GlobalUnlock((HGLOBAL)handle);
|
||||||
|
#pragma warning restore CA1416 // Validate platform compatibility
|
||||||
|
//WinNativeMethods.GlobalUnlock(handle);
|
||||||
|
}
|
||||||
|
else if (TWPlatform.IsLinux)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else if (TWPlatform.IsMacOSX)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new PlatformNotSupportedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Free(IntPtr handle)
|
|
||||||
{
|
|
||||||
if (handle == IntPtr.Zero) return;
|
|
||||||
|
|
||||||
if (_entryPoint.DSM_MemFree != null)
|
|
||||||
{
|
|
||||||
_entryPoint.DSM_MemFree(handle);
|
|
||||||
}
|
|
||||||
else if (TWPlatform.IsWindows)
|
|
||||||
{
|
|
||||||
WinNativeMethods.GlobalFree(handle);
|
|
||||||
}
|
|
||||||
else if (TWPlatform.IsLinux)
|
|
||||||
{
|
|
||||||
Marshal.FreeHGlobal(handle);
|
|
||||||
}
|
|
||||||
else if (TWPlatform.IsMacOSX)
|
|
||||||
{
|
|
||||||
Marshal.FreeHGlobal(handle);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new PlatformNotSupportedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IntPtr Lock(IntPtr handle)
|
|
||||||
{
|
|
||||||
if (handle == IntPtr.Zero) return IntPtr.Zero;
|
|
||||||
|
|
||||||
if (_entryPoint.DSM_MemLock != null)
|
|
||||||
{
|
|
||||||
return _entryPoint.DSM_MemLock(handle);
|
|
||||||
}
|
|
||||||
else if (TWPlatform.IsWindows)
|
|
||||||
{
|
|
||||||
return WinNativeMethods.GlobalLock(handle);
|
|
||||||
}
|
|
||||||
else if (TWPlatform.IsLinux)
|
|
||||||
{
|
|
||||||
return handle;
|
|
||||||
}
|
|
||||||
else if (TWPlatform.IsMacOSX)
|
|
||||||
{
|
|
||||||
return handle;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new PlatformNotSupportedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Unlock(IntPtr handle)
|
|
||||||
{
|
|
||||||
if (handle == IntPtr.Zero) return;
|
|
||||||
|
|
||||||
if (_entryPoint.DSM_MemUnlock != null)
|
|
||||||
{
|
|
||||||
_entryPoint.DSM_MemUnlock(handle);
|
|
||||||
}
|
|
||||||
else if (TWPlatform.IsWindows)
|
|
||||||
{
|
|
||||||
WinNativeMethods.GlobalUnlock(handle);
|
|
||||||
}
|
|
||||||
else if (TWPlatform.IsLinux)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
else if (TWPlatform.IsMacOSX)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new PlatformNotSupportedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ using System.Diagnostics;
|
|||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using System.Windows.Interop;
|
using System.Windows.Interop;
|
||||||
|
using Windows.Win32.Foundation;
|
||||||
using MSG = NTwain.Data.MSG;
|
using MSG = NTwain.Data.MSG;
|
||||||
|
|
||||||
namespace NTwain
|
namespace NTwain
|
||||||
@@ -83,11 +84,11 @@ namespace NTwain
|
|||||||
bool handled = false;
|
bool handled = false;
|
||||||
if (_state >= STATE.S5)
|
if (_state >= STATE.S5)
|
||||||
{
|
{
|
||||||
WIN_MESSAGE winMsg = new()
|
Windows.Win32.UI.WindowsAndMessaging.MSG winMsg = new()
|
||||||
{
|
{
|
||||||
hwnd = hWnd,
|
hwnd = (HWND)hWnd,
|
||||||
message = (uint)msg,
|
message = (uint)msg,
|
||||||
wParam = wParam,
|
wParam = TWPlatform.Is32bit ? new UIntPtr((uint)wParam.ToInt32()) : new UIntPtr((ulong)wParam.ToInt64()),
|
||||||
lParam = lParam
|
lParam = lParam
|
||||||
};
|
};
|
||||||
// no need to do another lock call when using marshal alloc
|
// no need to do another lock call when using marshal alloc
|
||||||
|
|||||||
Reference in New Issue
Block a user