mirror of
https://github.com/soukoku/ntwain.git
synced 2026-02-25 13:04:07 +08:00
Testing a basic xfer loop.
This commit is contained in:
@@ -1,3 +1,5 @@
|
|||||||
|
# For NTwain
|
||||||
|
|
||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (c) 2012 - 2023 Eugene Wang
|
Copyright (c) 2012 - 2023 Eugene Wang
|
||||||
@@ -21,10 +23,9 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|||||||
DEALINGS IN THE SOFTWARE.
|
DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
|
# Third Party Code Used
|
||||||
|
|
||||||
|
## For twaincs
|
||||||
# for twaincs
|
|
||||||
|
|
||||||
|
|
||||||
Copyright(C) 2013 - 2021 Kodak Alaris Inc.
|
Copyright(C) 2013 - 2021 Kodak Alaris Inc.
|
||||||
|
|
||||||
|
|||||||
@@ -24,9 +24,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NTwain", "src\NTwain\NTwain
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NTwain-temp", "src\NTwain-temp\NTwain-temp.csproj", "{A7020B90-5CE4-43EF-A75D-5E1F9B501CAC}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NTwain-temp", "src\NTwain-temp\NTwain-temp.csproj", "{A7020B90-5CE4-43EF-A75D-5E1F9B501CAC}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Console32", "samples\Console32\Console32.csproj", "{AAF9FE1B-B695-4AFD-A014-CA4DFDD06A79}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WinForm32", "samples\WinForm32\WinForm32.csproj", "{7792A94E-D0B4-440D-8BD5-CA1CA548782C}"
|
||||||
EndProject
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WinForm32", "samples\WinForm32\WinForm32.csproj", "{7792A94E-D0B4-440D-8BD5-CA1CA548782C}"
|
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
@@ -41,10 +39,6 @@ Global
|
|||||||
{A7020B90-5CE4-43EF-A75D-5E1F9B501CAC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{A7020B90-5CE4-43EF-A75D-5E1F9B501CAC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{A7020B90-5CE4-43EF-A75D-5E1F9B501CAC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{A7020B90-5CE4-43EF-A75D-5E1F9B501CAC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{A7020B90-5CE4-43EF-A75D-5E1F9B501CAC}.Release|Any CPU.Build.0 = Release|Any CPU
|
{A7020B90-5CE4-43EF-A75D-5E1F9B501CAC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{AAF9FE1B-B695-4AFD-A014-CA4DFDD06A79}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{AAF9FE1B-B695-4AFD-A014-CA4DFDD06A79}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{AAF9FE1B-B695-4AFD-A014-CA4DFDD06A79}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{AAF9FE1B-B695-4AFD-A014-CA4DFDD06A79}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{7792A94E-D0B4-440D-8BD5-CA1CA548782C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{7792A94E-D0B4-440D-8BD5-CA1CA548782C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{7792A94E-D0B4-440D-8BD5-CA1CA548782C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{7792A94E-D0B4-440D-8BD5-CA1CA548782C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{7792A94E-D0B4-440D-8BD5-CA1CA548782C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{7792A94E-D0B4-440D-8BD5-CA1CA548782C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
@@ -54,7 +48,6 @@ Global
|
|||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(NestedProjects) = preSolution
|
GlobalSection(NestedProjects) = preSolution
|
||||||
{AAF9FE1B-B695-4AFD-A014-CA4DFDD06A79} = {707B4313-8EF8-4D0F-A95E-590783422187}
|
|
||||||
{7792A94E-D0B4-440D-8BD5-CA1CA548782C} = {707B4313-8EF8-4D0F-A95E-590783422187}
|
{7792A94E-D0B4-440D-8BD5-CA1CA548782C} = {707B4313-8EF8-4D0F-A95E-590783422187}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Runtime.InteropServices.ComTypes;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace NTwain.Data
|
namespace NTwain.Data
|
||||||
@@ -621,9 +622,15 @@ namespace NTwain.Data
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
#if NETFRAMEWORK
|
#if NETFRAMEWORK
|
||||||
var bytes = new byte[Size];
|
// safe method but with 2 copies (arr and parsed string)
|
||||||
Marshal.Copy(locked, bytes, 0, bytes.Length);
|
var bytes = new byte[Size];
|
||||||
val = Encoding.UTF8.GetString(bytes);
|
Marshal.Copy(locked, bytes, 0, bytes.Length);
|
||||||
|
val = Encoding.UTF8.GetString(bytes);
|
||||||
|
|
||||||
|
//// unsafe method with 1 copy (does it work?)
|
||||||
|
//sbyte* bytes = (sbyte*)locked;
|
||||||
|
//var str = new string(bytes, 0, length, Encoding.UTF8);
|
||||||
|
//return str;
|
||||||
#else
|
#else
|
||||||
val = Marshal.PtrToStringUTF8(locked, (int)Size);
|
val = Marshal.PtrToStringUTF8(locked, (int)Size);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
340
src/NTwain/Native/BITMAP.cs
Normal file
340
src/NTwain/Native/BITMAP.cs
Normal file
@@ -0,0 +1,340 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace NTwain.Native
|
||||||
|
{
|
||||||
|
// this is a good read
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <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);
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the vertical dpi of the bitmap.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public float GetYDpi()
|
||||||
|
{
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the pointer to scan0 given the header pointer.
|
||||||
|
/// </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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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;
|
||||||
|
}
|
||||||
|
}
|
||||||
75
src/NTwain/Native/TIFF.cs
Normal file
75
src/NTwain/Native/TIFF.cs
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// TwainWorkingGroup.TWAIN
|
||||||
|
//
|
||||||
|
// This is a wrapper class for basic TWAIN functionality. It establishes
|
||||||
|
// behavior that every application should adhere to. It also hides OS
|
||||||
|
// specific details, so that toolkits or applications can use one unified
|
||||||
|
// interface to TWAIN.
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Author Date TWAIN Comment
|
||||||
|
// M.McLaughlin 17-May-2021 2.5.0.0 Updated to latest spec
|
||||||
|
// M.McLaughlin 13-Mar-2019 2.4.0.3 Add language code page support for strings
|
||||||
|
// M.McLaughlin 13-Nov-2015 2.4.0.0 Updated to latest spec
|
||||||
|
// M.McLaughlin 13-Sep-2015 2.3.1.2 DsmMem bug fixes
|
||||||
|
// M.McLaughlin 26-Aug-2015 2.3.1.1 Log fix and sync with TWAIN Direct
|
||||||
|
// M.McLaughlin 13-Mar-2015 2.3.1.0 Numerous fixes
|
||||||
|
// M.McLaughlin 13-Oct-2014 2.3.0.4 Added logging
|
||||||
|
// M.McLaughlin 24-Jun-2014 2.3.0.3 Stability fixes
|
||||||
|
// M.McLaughlin 21-May-2014 2.3.0.2 64-Bit Linux
|
||||||
|
// M.McLaughlin 27-Feb-2014 2.3.0.1 AnyCPU support
|
||||||
|
// M.McLaughlin 21-Oct-2013 2.3.0.0 Initial Release
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright (C) 2013-2021 Kodak Alaris Inc.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace NTwain.Native
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The TIFF file header.
|
||||||
|
/// Needed for supporting DAT.IMAGENATIVEXFER...
|
||||||
|
/// </summary>
|
||||||
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||||
|
struct TIFFHEADER
|
||||||
|
{
|
||||||
|
public ushort u8ByteOrder;
|
||||||
|
public ushort u16Version;
|
||||||
|
public uint u32OffsetFirstIFD;
|
||||||
|
public ushort u16u16IFD;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An individual TIFF Tag.
|
||||||
|
/// Needed for supporting DAT.IMAGENATIVEXFER...
|
||||||
|
/// </summary>
|
||||||
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||||
|
struct TIFFTAG
|
||||||
|
{
|
||||||
|
public ushort u16Tag;
|
||||||
|
public ushort u16Type;
|
||||||
|
public uint u32Count;
|
||||||
|
public uint u32Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -5,7 +5,11 @@ using System.Windows.Threading;
|
|||||||
|
|
||||||
namespace NTwain
|
namespace NTwain
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// An <see cref="IThreadMarshaller"/> that can be used
|
||||||
|
/// to integrate <see cref="TwainSession"/> with
|
||||||
|
/// an existing Winforms app.
|
||||||
|
/// </summary>
|
||||||
public class WinformMarshaller : IThreadMarshaller
|
public class WinformMarshaller : IThreadMarshaller
|
||||||
{
|
{
|
||||||
private readonly Control control;
|
private readonly Control control;
|
||||||
@@ -26,6 +30,11 @@ namespace NTwain
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An <see cref="IThreadMarshaller"/> that can be used
|
||||||
|
/// to integrate <see cref="TwainSession"/> with
|
||||||
|
/// an existing WPF app.
|
||||||
|
/// </summary>
|
||||||
public class WpfMarshaller : IThreadMarshaller
|
public class WpfMarshaller : IThreadMarshaller
|
||||||
{
|
{
|
||||||
private readonly Dispatcher dispatcher;
|
private readonly Dispatcher dispatcher;
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ namespace NTwain
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// No marshalling occurs. Invokes happen right in place.
|
/// No marshalling occurs. Invokes happen right in place synchronously.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class InPlaceMarshaller : IThreadMarshaller
|
public class InPlaceMarshaller : IThreadMarshaller
|
||||||
{
|
{
|
||||||
|
|||||||
47
src/NTwain/TransferErrorEventArgs.cs
Normal file
47
src/NTwain/TransferErrorEventArgs.cs
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
using NTwain.Data;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace NTwain
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Contains TWAIN codes and source status when an error is encountered during transfer.
|
||||||
|
/// </summary>
|
||||||
|
public class TransferErrorEventArgs : EventArgs
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="TransferErrorEventArgs"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="error">The error.</param>
|
||||||
|
public TransferErrorEventArgs(Exception error)
|
||||||
|
{
|
||||||
|
Exception = error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="TransferErrorEventArgs"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="code">The code.</param>
|
||||||
|
/// <param name="status">Additional status info from TWAIN.</param>
|
||||||
|
public TransferErrorEventArgs(STS code, string? info)
|
||||||
|
{
|
||||||
|
Code = code;
|
||||||
|
Info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the return code or condition code from the transfer.
|
||||||
|
/// </summary>
|
||||||
|
public STS Code { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the additional status info from TWAIN.
|
||||||
|
/// </summary>
|
||||||
|
public string? Info { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the exception if the error is from some exception
|
||||||
|
/// and not from TWAIN.
|
||||||
|
/// </summary>
|
||||||
|
public Exception? Exception { get; private set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -135,5 +135,10 @@ namespace NTwain
|
|||||||
/// Fires when the source has some device event happening.
|
/// Fires when the source has some device event happening.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event Action<TwainSession, TW_DEVICEEVENT>? DeviceEvent;
|
public event Action<TwainSession, TW_DEVICEEVENT>? DeviceEvent;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fires when there's an error during transfer.
|
||||||
|
/// </summary>
|
||||||
|
public event EventHandler<TransferErrorEventArgs>? TransferError;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,8 @@ namespace NTwain
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Registers this session for use in a WPF UI thread.
|
/// Registers this session for use in a WPF UI thread.
|
||||||
|
/// This requires the hwnd used in <see cref="OpenDSM(IntPtr)"/>
|
||||||
|
/// be a valid WPF window handle.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void AddWpfHook()
|
public void AddWpfHook()
|
||||||
{
|
{
|
||||||
@@ -57,12 +59,11 @@ namespace NTwain
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool System.Windows.Forms.IMessageFilter.PreFilterMessage(ref System.Windows.Forms.Message m)
|
bool IMessageFilter.PreFilterMessage(ref Message m)
|
||||||
{
|
{
|
||||||
return CheckIfTwainMessage(m.HWnd, m.Msg, m.WParam, m.LParam);
|
return CheckIfTwainMessage(m.HWnd, m.Msg, m.WParam, m.LParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
// wpf use with HwndSource.FromHwnd(Handle).AddHook(
|
|
||||||
IntPtr WpfHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
|
IntPtr WpfHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
|
||||||
{
|
{
|
||||||
handled = CheckIfTwainMessage(hwnd, msg, wParam, lParam);
|
handled = CheckIfTwainMessage(hwnd, msg, wParam, lParam);
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
using NTwain.Data;
|
using NTwain.Data;
|
||||||
|
using NTwain.Triplets;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
@@ -10,5 +12,94 @@ namespace NTwain
|
|||||||
|
|
||||||
partial class TwainSession
|
partial class TwainSession
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Start the transfer loop.
|
||||||
|
/// This should be called after receiving
|
||||||
|
/// <see cref="MSG.XFERREADY"/> in the background thread.
|
||||||
|
/// </summary>
|
||||||
|
void EnterTransferRoutine()
|
||||||
|
{
|
||||||
|
// default options if source don't support them or whatever
|
||||||
|
bool xferImage = true;
|
||||||
|
bool xferAudio = false;
|
||||||
|
var imgXferMech = TWSX.NATIVE;
|
||||||
|
var audXferMech = TWSX.NATIVE;
|
||||||
|
if (DGControl.XferGroup.Get(ref _appIdentity, ref _currentDS, out DG xferType) == STS.SUCCESS)
|
||||||
|
{
|
||||||
|
xferAudio = (xferType & DG.AUDIO) == DG.AUDIO;
|
||||||
|
var dsName = _currentDS.ProductName.ToString();
|
||||||
|
// check for Plustek OpticSlim 2680H, this scanner returns wrong xferGroup after first scanning
|
||||||
|
if (dsName.IndexOf("Plustek", StringComparison.OrdinalIgnoreCase) > -1 &&
|
||||||
|
dsName.IndexOf("OpticSlim", StringComparison.OrdinalIgnoreCase) > -1 &&
|
||||||
|
dsName.IndexOf("2680H", StringComparison.OrdinalIgnoreCase) > -1)
|
||||||
|
{
|
||||||
|
xferImage = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// some DS end up getting none but we will assume it's image
|
||||||
|
xferImage = xferType == 0 || (xferType & DG.IMAGE) == DG.IMAGE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//if (xferImage)
|
||||||
|
//{
|
||||||
|
// imgXferMech = session.CurrentSource.Capabilities.ICapXferMech.GetCurrent();
|
||||||
|
//}
|
||||||
|
//if (xferAudio)
|
||||||
|
//{
|
||||||
|
// audXferMech = session.CurrentSource.Capabilities.ACapXferMech.GetCurrent();
|
||||||
|
//}
|
||||||
|
|
||||||
|
TW_PENDINGXFERS pending = default;
|
||||||
|
var rc = DGControl.PendingXfers.Get(ref _appIdentity, ref _currentDS, ref pending);
|
||||||
|
if (rc == STS.SUCCESS)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
// cancel for now
|
||||||
|
//rc = DGControl.PendingXfers.Reset(ref _appIdentity, ref _currentDS, ref pending);
|
||||||
|
|
||||||
|
|
||||||
|
rc = DGControl.PendingXfers.EndXfer(ref _appIdentity, ref _currentDS, ref pending);
|
||||||
|
|
||||||
|
//if (xferType.HasFlag(DG.AUDIO))
|
||||||
|
//{
|
||||||
|
// DoTransferAudio();
|
||||||
|
//}
|
||||||
|
//else // just defaults to image
|
||||||
|
//{
|
||||||
|
// DoTransferImage();
|
||||||
|
//}
|
||||||
|
|
||||||
|
} while (rc == STS.SUCCESS && pending.Count != 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
HandleNonSuccessXferCode(rc);
|
||||||
|
}
|
||||||
|
_uiThreadMarshaller.BeginInvoke(() =>
|
||||||
|
{
|
||||||
|
DisableSource();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleNonSuccessXferCode(STS rc)
|
||||||
|
{
|
||||||
|
switch (rc)
|
||||||
|
{
|
||||||
|
case STS.SUCCESS:
|
||||||
|
case STS.XFERDONE:
|
||||||
|
case STS.CANCEL:
|
||||||
|
// ok to keep going
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
var status = GetLastStatus(false);
|
||||||
|
var text = GetStatusText(status);
|
||||||
|
// TODO: raise error event
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -97,8 +97,8 @@ namespace NTwain
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal IntPtr _hwnd;
|
internal IntPtr _hwnd;
|
||||||
internal TW_USERINTERFACE _userInterface; // kept around for disable use
|
internal TW_USERINTERFACE _userInterface; // kept around for disable to use
|
||||||
TW_EVENT _procEvent = default; // kept here so the alloc/free only happens once
|
TW_EVENT _procEvent; // kept here so the alloc/free only happens once
|
||||||
// test threads a bit
|
// test threads a bit
|
||||||
readonly BlockingCollection<MSG> _bgPendingMsgs = new();
|
readonly BlockingCollection<MSG> _bgPendingMsgs = new();
|
||||||
private readonly IThreadMarshaller _uiThreadMarshaller;
|
private readonly IThreadMarshaller _uiThreadMarshaller;
|
||||||
@@ -138,6 +138,11 @@ namespace NTwain
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MSG.XFERREADY:
|
case MSG.XFERREADY:
|
||||||
|
_uiThreadMarshaller.Invoke(() =>
|
||||||
|
{
|
||||||
|
State = STATE.S6;
|
||||||
|
});
|
||||||
|
EnterTransferRoutine();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user