是否可以在TWAIN中强制扫描仪将区域设置为整个宽度?

我正在编写一个需要在.net中扫描的应用程序( c# version 4.0 ,Visual Studio 2010)。 我正在使用TWAIN API进行扫描,我的布局function有问题。 以下代码在Microtek i800CanoScan 9000FMicrotek Artix Scan F2运行得非常好,但是当我在Epson Perfection V700上运行时,出现了一些非常奇怪的事情。

即使我将布局的左边距设置为0 ,图像的左边缘也会被切断。 我尝试将其设置为负值,但这没有任何区别。 似乎有一些奇怪的东西,它迫使它成为一个电影大小(也许是因为我正在开灯)。 如果我使用扫描仪附带的工具,它允许我选择包含两个边缘的区域(并打开灯),因此必须可以。 此外,顶部和底部坐标工作得非常好。

所以我的问题是……

有谁知道我可以扫描整个宽度的任何方式? 在TWAIN中是否有其他设置我可以先设置让它忘记纸张尺寸? (我尝试将PaperDetectable设置为false,但它没有任何区别)。

另外一件事: 如果我没有设置布局,它仍然会切断边缘的图片(只是不是顶部和底部)但是如果我也没有设置指示灯(或者我没有设置指示灯但是我没有设置大小)它做我所期望的:专门从最左边扫描整个图片(但问题是,我真的需要光线和扫描的整个宽度 – 当然,这不是太多问题。 ..)。


这是代码(它是1个窗体窗体应用程序的代码,后面有一个按钮):

 using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; using System.Linq; using System.Windows.Forms; namespace TwainLayoutWindowsFormsApplication { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { TwainIdentity appid = null; TwainIdentity scanner = null; bool enabled = false; try { appid = InitializeTwain(Handle); scanner = GetSource(appid, "EPSON Perfection V700/V750"); Open(appid, scanner); SetLightOn(appid, scanner); SetLayout(appid, scanner); Enable(appid, scanner, Handle); enabled = true; var bmps = Scan(appid, scanner); Disable(appid, scanner); enabled = false; bmps.First().Save(@"c:\users\public\scan.bmp", ImageFormat.Bmp); } catch(Exception ex) { MessageBox.Show(ex.Message); } finally { if (appid != null && scanner != null) { if (enabled) { try { Disable(appid, scanner); } catch(InvalidOperationException) { } } Close(appid, scanner); } } } private static void SetLayout(TwainIdentity appid, TwainIdentity scanner) { TwainImageLayout layout = new TwainImageLayout(); var rc = NativeMethods.DSilayout(appid, scanner, TwainDataGroups.Image, TwainDataArgumentType.ImageLayout, TwainMessage.Get, layout); // 1 inch from the top and 0 from the left layout.Frame.Top = new TwainFix32(); layout.Frame.Top.Whole = 1; layout.Frame.Left = new TwainFix32(); layout.Frame.Left.Whole = 0; layout.Frame.Right = new TwainFix32(); layout.Frame.Right.Whole = 6; layout.Frame.Bottom = new TwainFix32(); layout.Frame.Bottom.Whole = 3; layout.FrameNumber = 1; layout.PageNumber = 1; layout.DocumentNumber = 1; rc = NativeMethods.DSilayout(appid, scanner, TwainDataGroups.Image, TwainDataArgumentType.ImageLayout, TwainMessage.Set, layout); if (rc != TwainReturnCode.Success) throw new InvalidOperationException("Failed to set layout"); var s = new TwainStatus(); rc = NativeMethods.DSstatus(appid, scanner, TwainDataGroups.Control, TwainDataArgumentType.Status, TwainMessage.Get, s); if (rc != TwainReturnCode.Success) throw new InvalidOperationException("Failed to get layout"); } private IEnumerable Scan(TwainIdentity appid, TwainIdentity scanner) { var pictures = new List(); TwainReturnCode rc; IntPtr hbitmap; var pxfr = new TwainPendingXfers(); do { pxfr.Count = 10; hbitmap = IntPtr.Zero; var iinf = new TwainImageInfo(); rc = NativeMethods.DSiinf(appid, scanner, TwainDataGroups.Image, TwainDataArgumentType.ImageInfo, TwainMessage.Get, iinf); if (rc != TwainReturnCode.Success) throw new InvalidOperationException("Could not INF"); rc = NativeMethods.DSixfer(appid, scanner, TwainDataGroups.Image, TwainDataArgumentType.ImageNativeXfer, TwainMessage.Get, ref hbitmap); if (rc != TwainReturnCode.XferDone) throw new InvalidOperationException("Could DSI XFER"); rc = NativeMethods.DSpxfer(appid, scanner, TwainDataGroups.Control, TwainDataArgumentType.PendingXfers, TwainMessage.EndXfer, pxfr); if (rc != TwainReturnCode.Success) throw new InvalidOperationException("Could DSP XFER"); var bmp = TwainBitmapConvertor.ToBitmap(hbitmap); pictures.Add(bmp); } while (pxfr.Count != 0); NativeMethods.DSpxfer(appid, scanner, TwainDataGroups.Control, TwainDataArgumentType.PendingXfers, TwainMessage.StopFeeder, pxfr); return pictures; } private static void Enable(TwainIdentity appid, TwainIdentity scanner, IntPtr hwnd) { var guif = new TwainUserInterface(); guif.ShowUI = 0; guif.ModalUI = 1; guif.ParentHand = hwnd; var rc = NativeMethods.DSuserif(appid, scanner, TwainDataGroups.Control, TwainDataArgumentType.UserInterface, TwainMessage.EnableDS, guif); if (rc != TwainReturnCode.Success) throw new InvalidOperationException("Could not enable"); } private static void Disable(TwainIdentity appid, TwainIdentity scanner) { var guif = new TwainUserInterface(); var rc = NativeMethods.DSuserif(appid, scanner, TwainDataGroups.Control, TwainDataArgumentType.UserInterface, TwainMessage.DisableDS, guif); if (rc != TwainReturnCode.Success) throw new InvalidOperationException("Could not disable"); } private static void SetLightOn(TwainIdentity appid, TwainIdentity scanner) { using (var capability = new TwainCapability(TwainCapabilityType.Lightpath, 1)) { var rc = NativeMethods.DScap(appid, scanner, TwainDataGroups.Control, TwainDataArgumentType.Capability, TwainMessage.Set, capability); if (rc != TwainReturnCode.Success) throw new InvalidOperationException("Failed to set light"); } } private static void Close(TwainIdentity appid, TwainIdentity scanner) { NativeMethods.DSMident(appid, IntPtr.Zero, TwainDataGroups.Control, TwainDataArgumentType.Identity, TwainMessage.CloseDS, scanner); } private static void Open(TwainIdentity appid, TwainIdentity scanner) { var rc = NativeMethods.DSMident(appid, IntPtr.Zero, TwainDataGroups.Control, TwainDataArgumentType.Identity, TwainMessage.OpenDS, scanner); if (rc != TwainReturnCode.Success) throw new InvalidOperationException("Failed to open"); } private static TwainIdentity InitializeTwain(IntPtr hwndp) { var appid = new TwainIdentity(); appid.Version.MajorNum = 1; appid.Version.MinorNum = 0; appid.Version.Language = 13; appid.Version.Country = 1; appid.Version.Info = "Test"; appid.Id = IntPtr.Zero; appid.ProtocolMajor = 1; appid.ProtocolMinor = 9; appid.SupportedGroups = (int)(TwainDataGroups.Image | TwainDataGroups.Control); appid.Manufacturer = "Test Manufacturer"; appid.ProductFamily = "Test Family"; appid.ProductName = "Test Product"; var rc = NativeMethods.DSMparent(appid, IntPtr.Zero, TwainDataGroups.Control, TwainDataArgumentType.Parent, TwainMessage.OpenDSM, ref hwndp); if (rc != TwainReturnCode.Success) throw new InvalidOperationException("Could Not DSMParent"); return appid; } private static TwainIdentity GetSource(TwainIdentity appid, string name) { var device = new TwainIdentity { Id = IntPtr.Zero }; var rc = NativeMethods.DSMentry(appid, IntPtr.Zero, TwainDataGroups.Control, TwainDataArgumentType.Identity, TwainMessage.GetFirst, device); if (rc != TwainReturnCode.EndOfList && device.ProductName.Equals(name, StringComparison.OrdinalIgnoreCase)) { return device; } while (rc != TwainReturnCode.EndOfList) { device = new TwainIdentity { Id = IntPtr.Zero }; rc = NativeMethods.DSMentry(appid, IntPtr.Zero, TwainDataGroups.Control, TwainDataArgumentType.Identity, TwainMessage.GetNext, device); if (rc != TwainReturnCode.EndOfList && device.ProductName.Equals(name, StringComparison.OrdinalIgnoreCase)) { return device; } } throw new InvalidOperationException("Could not find device"); } } } 

为了完整性,这里是我用来将HBITMAP转换为System.Drawing.Bitmap的代码 :

 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Diagnostics; using System.Drawing; using System.Runtime.InteropServices; using System.Globalization; namespace TwainLayoutWindowsFormsApplication { internal static class TwainBitmapConvertor { [StructLayout(LayoutKind.Sequential, Pack = 2)] private class BitmapInfoHeader { public int Size; public int Width; public int Height; public short Planes; public short BitCount; public int Compression; public int SizeImage; public int XPelsPerMeter; public int YPelsPerMeter; public int ClrUsed; public int ClrImportant; } internal static Bitmap ToBitmap(IntPtr dibHandle) { var bitmapPointer = NativeMethods.GlobalLock(dibHandle); var bitmapInfo = new BitmapInfoHeader(); Marshal.PtrToStructure(bitmapPointer, bitmapInfo); var rectangle = new Rectangle(); rectangle.X = rectangle.Y = 0; rectangle.Width = bitmapInfo.Width; rectangle.Height = bitmapInfo.Height; if (bitmapInfo.SizeImage == 0) { bitmapInfo.SizeImage = ((((bitmapInfo.Width * bitmapInfo.BitCount) + 31) & ~31) >> 3) * bitmapInfo.Height; } // The following code only works on x86 if (Marshal.SizeOf(typeof(IntPtr)) != 4) throw new NotSupportedException("Only x86 is supported"); int pixelInfoPointer = bitmapInfo.ClrUsed; if ((pixelInfoPointer == 0) && (bitmapInfo.BitCount <= 8)) { pixelInfoPointer = 1 << bitmapInfo.BitCount; } pixelInfoPointer = (pixelInfoPointer * 4) + bitmapInfo.Size + bitmapPointer.ToInt32(); IntPtr pixelInfoIntPointer = new IntPtr(pixelInfoPointer); var bitmap = new Bitmap(rectangle.Width, rectangle.Height); using (Graphics graphics = Graphics.FromImage(bitmap)) { IntPtr hdc = graphics.GetHdc(); try { NativeMethods.SetDIBitsToDevice(hdc, 0, 0, rectangle.Width, rectangle.Height, 0, 0, 0, rectangle.Height, pixelInfoIntPointer, bitmapPointer, 0); } finally { graphics.ReleaseHdc(hdc); } } bitmap.SetResolution(PpmToDpi(bitmapInfo.XPelsPerMeter), PpmToDpi(bitmapInfo.YPelsPerMeter)); NativeMethods.GlobalUnlock(dibHandle); NativeMethods.GlobalFree(dibHandle); return bitmap; } private static float PpmToDpi(double pixelsPerMeter) { double pixelsPerMillimeter = (double)pixelsPerMeter / 1000.0; double dotsPerInch = pixelsPerMillimeter * 25.4; return (float)Math.Round(dotsPerInch, 2); } } } 

这是p / invokes:

 using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; namespace TwainLayoutWindowsFormsApplication { internal static class NativeMethods { [DllImport("kernel32.dll", ExactSpelling = true)] internal static extern IntPtr GlobalAlloc(int flags, int size); [DllImport("kernel32.dll", ExactSpelling = true)] internal static extern IntPtr GlobalLock(IntPtr handle); [DllImport("kernel32.dll", ExactSpelling = true)] internal static extern bool GlobalUnlock(IntPtr handle); [DllImport("kernel32.dll", ExactSpelling = true)] internal static extern IntPtr GlobalFree(IntPtr handle); [DllImport("gdi32.dll", ExactSpelling = true)] public static extern int SetDIBitsToDevice(IntPtr hdc, int xdst, int ydst, int width, int height, int xsrc, int ysrc, int start, int lines, IntPtr bitsptr, IntPtr bmiptr, int color); [DllImport("twain_32.dll", EntryPoint = "#1")] internal static extern TwainReturnCode DSMparent([In, Out] TwainIdentity origin, IntPtr zeroptr, TwainDataGroups dg, TwainDataArgumentType dat, TwainMessage msg, ref IntPtr refptr); [DllImport("twain_32.dll", EntryPoint = "#1")] internal static extern TwainReturnCode DSMident([In, Out] TwainIdentity origin, IntPtr zeroptr, TwainDataGroups dg, TwainDataArgumentType dat, TwainMessage msg, [In, Out] TwainIdentity idds); [DllImport("twain_32.dll", EntryPoint = "#1")] internal static extern TwainReturnCode DSMentry([In, Out] TwainIdentity origin, IntPtr zeroptr, TwainDataGroups dg, TwainDataArgumentType dat, TwainMessage msg, [In, Out] TwainIdentity idds); [DllImport("twain_32.dll", EntryPoint = "#1")] internal static extern TwainReturnCode DSMstatus([In, Out] TwainIdentity origin, IntPtr zeroptr, TwainDataGroups dg, TwainDataArgumentType dat, TwainMessage msg, [In, Out] TwainStatus dsmstat); [DllImport("twain_32.dll", EntryPoint = "#1")] internal static extern TwainReturnCode DSuserif([In, Out] TwainIdentity origin, [In, Out] TwainIdentity dest, TwainDataGroups dg, TwainDataArgumentType dat, TwainMessage msg, TwainUserInterface guif); [DllImport("twain_32.dll", EntryPoint = "#1")] internal static extern TwainReturnCode DSevent([In, Out] TwainIdentity origin, [In, Out] TwainIdentity dest, TwainDataGroups dg, TwainDataArgumentType dat, TwainMessage msg, ref TwainEvent evt); [DllImport("twain_32.dll", EntryPoint = "#1")] internal static extern TwainReturnCode DSstatus([In, Out] TwainIdentity origin, [In] TwainIdentity dest, TwainDataGroups dg, TwainDataArgumentType dat, TwainMessage msg, [In, Out] TwainStatus dsmstat); [DllImport("twain_32.dll", EntryPoint = "#1")] internal static extern TwainReturnCode DScap([In, Out] TwainIdentity origin, [In] TwainIdentity dest, TwainDataGroups dg, TwainDataArgumentType dat, TwainMessage msg, [In, Out] TwainCapability capa); [DllImport("twain_32.dll", EntryPoint = "#1")] internal static extern TwainReturnCode DSiinf([In, Out] TwainIdentity origin, [In] TwainIdentity dest, TwainDataGroups dg, TwainDataArgumentType dat, TwainMessage msg, [In, Out] TwainImageInfo imginf); [DllImport("twain_32.dll", EntryPoint = "#1")] internal static extern TwainReturnCode DSixfer([In, Out] TwainIdentity origin, [In] TwainIdentity dest, TwainDataGroups dg, TwainDataArgumentType dat, TwainMessage msg, ref IntPtr hbitmap); [DllImport("twain_32.dll", EntryPoint = "#1")] internal static extern TwainReturnCode DSMemixfer([In, Out] TwainIdentity origin, [In] TwainIdentity dest, TwainDataGroups dg, TwainDataArgumentType dat, TwainMessage msg, [In, Out] TwainImageMemXfer memxfr); [DllImport("twain_32.dll", EntryPoint = "#1")] internal static extern TwainReturnCode DSpxfer([In, Out] TwainIdentity origin, [In] TwainIdentity dest, TwainDataGroups dg, TwainDataArgumentType dat, TwainMessage msg, [In, Out] TwainPendingXfers pxfr); [DllImport("twain_32.dll", EntryPoint = "#1")] internal static extern TwainReturnCode DSilayout([In, Out] TwainIdentity origin, [In] TwainIdentity dest, TwainDataGroups dg, TwainDataArgumentType dat, TwainMessage msg, [In, Out] TwainImageLayout layout); [DllImport("twain_32.dll", EntryPoint = "#1")] internal static extern TwainReturnCode DSMEntry([In, Out] TwainIdentity origin, [In] TwainIdentity dest, TwainDataGroups dg, TwainDataArgumentType dat, TwainMessage msg, [In, Out] TwainSetupFileXfer fileXf); } } 

最后,需要工作的其他东西(结构和诸如此类的东西):

 using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; namespace TwainLayoutWindowsFormsApplication { [StructLayout(LayoutKind.Sequential, Pack = 2, CharSet = CharSet.Ansi)] internal class TwainIdentity { public IntPtr Id; public TwainVersion Version; public short ProtocolMajor; public short ProtocolMinor; public int SupportedGroups; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 34)] public string Manufacturer; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 34)] public string ProductFamily; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 34)] public string ProductName; } internal enum TwainReturnCode : short { Success = 0x0000, Failure = 0x0001, CheckStatus = 0x0002, Cancel = 0x0003, DSEvent = 0x0004, NotDSEvent = 0x0005, XferDone = 0x0006, EndOfList = 0x0007, InfoNotSupported = 0x0008, DataNotAvailable = 0x0009 } [StructLayout(LayoutKind.Sequential, Pack = 2, CharSet = CharSet.Ansi)] internal struct TwainVersion { public short MajorNum; public short MinorNum; public short Language; public short Country; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 34)] public string Info; } [Flags] internal enum TwainDataGroups : short { Control = 0x0001, Image = 0x0002, Audio = 0x0004 } [StructLayout(LayoutKind.Sequential, Pack = 2)] internal struct TwainEvent { public IntPtr EventPtr; public short Message; } internal enum TwainDataArgumentType : short { Null = 0x0000, Capability = 0x0001, Event = 0x0002, Identity = 0x0003, Parent = 0x0004, PendingXfers = 0x0005, SetupMemXfer = 0x0006, SetupFileXfer = 0x0007, Status = 0x0008, UserInterface = 0x0009, XferGroup = 0x000a, TwunkIdentity = 0x000b, CustomDSData = 0x000c, DeviceEvent = 0x000d, FileSystem = 0x000e, PassThru = 0x000f, ImageInfo = 0x0101, ImageLayout = 0x0102, ImageMemXfer = 0x0103, ImageNativeXfer = 0x0104, ImageFileXfer = 0x0105, CieColor = 0x0106, GrayResponse = 0x0107, RGBResponse = 0x0108, JpegCompression = 0x0109, Palette8 = 0x010a, ExtImageInfo = 0x010b, SetupFileXfer2 = 0x0301 } internal enum TwainMessage : short { Null = 0x0000, Get = 0x0001, GetCurrent = 0x0002, GetDefault = 0x0003, GetFirst = 0x0004, GetNext = 0x0005, Set = 0x0006, Reset = 0x0007, QuerySupport = 0x0008, XFerReady = 0x0101, CloseDSReq = 0x0102, CloseDSOK = 0x0103, DeviceEvent = 0x0104, CheckStatus = 0x0201, OpenDSM = 0x0301, CloseDSM = 0x0302, OpenDS = 0x0401, CloseDS = 0x0402, UserSelect = 0x0403, DisableDS = 0x0501, EnableDS = 0x0502, EnableDSUIOnly = 0x0503, ProcessEvent = 0x0601, EndXfer = 0x0701, StopFeeder = 0x0702, ChangeDirectory = 0x0801, CreateDirectory = 0x0802, Delete = 0x0803, FormatMedia = 0x0804, GetClose = 0x0805, GetFirstFile = 0x0806, GetInfo = 0x0807, GetNextFile = 0x0808, Rename = 0x0809, Copy = 0x080A, AutoCaptureDir = 0x080B, PassThru = 0x0901 } [StructLayout(LayoutKind.Sequential, Pack = 4)] internal struct TwainWindowMessage { public IntPtr hwnd; public int message; public IntPtr wParam; public IntPtr lParam; public int time; public int x; public int y; } internal enum TwainOn : short { Array = 0x0003, Enum = 0x0004, One = 0x0005, Range = 0x0006, DontCare = -1 } internal enum TwainCapabilityType : short { XferCount = 0x0001, ICompression = 0x0100, IPixelType = 0x0101, IUnits = 0x0102, IXferMech = 0x0103, Author = 0x1000, Caption = 0x1001, FeederEnabled = 0x1002, FeederLoaded = 0x1003, Timedate = 0x1004, SupportedCapabilities = 0x1005, Extendedcaps = 0x1006, AutoFeed = 0x1007, ClearPage = 0x1008, FeedPage = 0x1009, RewindPage = 0x100a, Indicators = 0x100b, SupportedCapsExt = 0x100c, PaperDetectable = 0x100d, UIControllable = 0x100e, DeviceOnline = 0x100f, AutoScan = 0x1010, ThumbnailsEnabled = 0x1011, Duplex = 0x1012, DuplexEnabled = 0x1013, Enabledsuionly = 0x1014, CustomdsData = 0x1015, Endorser = 0x1016, JobControl = 0x1017, Alarms = 0x1018, AlarmVolume = 0x1019, AutomaticCapture = 0x101a, TimeBeforeFirstCapture = 0x101b, TimeBetweenCaptures = 0x101c, ClearBuffers = 0x101d, MaxBatchBuffers = 0x101e, DeviceTimeDate = 0x101f, PowerSupply = 0x1020, CameraPreviewUI = 0x1021, DeviceEvent = 0x1022, SerialNumber = 0x1024, Printer = 0x1026, PrinterEnabled = 0x1027, PrinterIndex = 0x1028, PrinterMode = 0x1029, PrinterString = 0x102a, PrinterSuffix = 0x102b, Language = 0x102c, FeederAlignment = 0x102d, FeederOrder = 0x102e, ReAcquireAllowed = 0x1030, BatteryMinutes = 0x1032, BatteryPercentage = 0x1033, CameraSide = 0x1034, Segmented = 0x1035, CameraEnabled = 0x1036, CameraOrder = 0x1037, MicrEnabled = 0x1038, FeederPrep = 0x1039, Feederpocket = 0x103a, Autobright = 0x1100, Brightness = 0x1101, Contrast = 0x1103, CustHalftone = 0x1104, ExposureTime = 0x1105, Filter = 0x1106, Flashused = 0x1107, Gamma = 0x1108, Halftones = 0x1109, Highlight = 0x110a, ImageFileFormat = 0x110c, LampState = 0x110d, LightSource = 0x110e, Orientation = 0x1110, PhysicalWidth = 0x1111, PhysicalHeight = 0x1112, Shadow = 0x1113, Frames = 0x1114, XNativeResolution = 0x1116, YNativeResolution = 0x1117, XResolution = 0x1118, YResolution = 0x1119, MaxFrames = 0x111a, Tiles = 0x111b, Bitorder = 0x111c, Ccittkfactor = 0x111d, Lightpath = 0x111e, Pixelflavor = 0x111f, Planarchunky = 0x1120, Rotation = 0x1121, Supportedsizes = 0x1122, Threshold = 0x1123, Xscaling = 0x1124, Yscaling = 0x1125, Bitordercodes = 0x1126, Pixelflavorcodes = 0x1127, Jpegpixeltype = 0x1128, Timefill = 0x112a, BitDepth = 0x112b, Bitdepthreduction = 0x112c, Undefinedimagesize = 0x112d, Imagedataset = 0x112e, Extimageinfo = 0x112f, Minimumheight = 0x1130, Minimumwidth = 0x1131, Fliprotation = 0x1136, Barcodedetectionenabled = 0x1137, Supportedbarcodetypes = 0x1138, Barcodemaxsearchpriorities = 0x1139, Barcodesearchpriorities = 0x113a, Barcodesearchmode = 0x113b, Barcodemaxretries = 0x113c, Barcodetimeout = 0x113d, Zoomfactor = 0x113e, Patchcodedetectionenabled = 0x113f, Supportedpatchcodetypes = 0x1140, Patchcodemaxsearchpriorities = 0x1141, Patchcodesearchpriorities = 0x1142, Patchcodesearchmode = 0x1143, Patchcodemaxretries = 0x1144, Patchcodetimeout = 0x1145, Flashused2 = 0x1146, Imagefilter = 0x1147, Noisefilter = 0x1148, Overscan = 0x1149, Automaticborderdetection = 0x1150, Automaticdeskew = 0x1151, Automaticrotate = 0x1152, Jpegquality = 0x1153, Feedertype = 0x1154, Iccprofile = 0x1155, Autosize = 0x1156, AutomaticCropUsesFrame = 0x1157, AutomaticLengthDetection = 0x1158, AutomaticColorEnabled = 0x1159, AutomaticColorNonColorPixelType = 0x115a, ColorManagementEnabled = 0x115b, ImageMerge = 0x115c, ImageMergeHeightThreshold = 0x115d, SupoortedExtImageInfo = 0x115e, Audiofileformat = 0x1201, Xfermech = 0x1202 } internal enum TwainType : short { Int8 = 0x0000, Int16 = 0x0001, Int32 = 0x0002, UInt8 = 0x0003, UInt16 = 0x0004, UInt32 = 0x0005, Bool = 0x0006, Fix32 = 0x0007, Frame = 0x0008, Str32 = 0x0009, Str64 = 0x000a, Str128 = 0x000b, Str255 = 0x000c, Str1024 = 0x000d, Str512 = 0x000e } [StructLayout(LayoutKind.Sequential, Pack = 2)] internal class TwainStatus { public short ConditionCode; public short Reserved; } [StructLayout(LayoutKind.Sequential, Pack = 2)] internal class TwainUserInterface { public short ShowUI; public short ModalUI; public IntPtr ParentHand; } [StructLayout(LayoutKind.Sequential, Pack = 2)] internal class TwainImageInfo { public int XResolution; public int YResolution; public int ImageWidth; public int ImageLength; public short SamplesPerPixel; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public short[] BitsPerSample; public short BitsPerPixel; public short Planar; public short PixelType; public short Compression; } [StructLayout(LayoutKind.Sequential, Pack = 2)] internal class TwMemory { public uint Flags; public uint Length; IntPtr TheMem; } [StructLayout(LayoutKind.Sequential, Pack = 2)] internal class TwainImageMemXfer { public ushort Compression; public uint BytesPerRow; public uint Columns; public uint Rows; public uint XOffset; public uint YOffset; public uint BytesWritten; [MarshalAs(UnmanagedType.Struct)] TwMemory Memory; } [StructLayout(LayoutKind.Sequential, Pack = 2)] internal struct TwainFix32 { public short Whole; public ushort Frac; } [StructLayout(LayoutKind.Sequential, Pack = 2)] internal class TwainFrame { public TwainFix32 Left; public TwainFix32 Top; public TwainFix32 Right; public TwainFix32 Bottom; } [StructLayout(LayoutKind.Sequential, Pack = 2)] internal class TwainImageLayout { public TwainFrame Frame; public int DocumentNumber; public int PageNumber; public int FrameNumber; } [StructLayout(LayoutKind.Sequential, Pack = 2)] internal class TwainPendingXfers { public short Count; public int EOJ; } [StructLayout(LayoutKind.Sequential, Pack = 2)] internal class TwainSetupFileXfer { [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 255)] public string FileName; public ushort Format; public short VRefNum; } [StructLayout(LayoutKind.Sequential, Pack = 2)] internal class TwainCapability : IDisposable { internal TwainCapability(TwainCapabilityType cap) { Cap = (short)cap; ConType = -1; } internal TwainCapability(TwainCapabilityType cap, short sval) { Cap = (short)cap; ConType = (short)TwainOn.One; Handle = NativeMethods.GlobalAlloc(0x42, 6); IntPtr pv = NativeMethods.GlobalLock(Handle); Marshal.WriteInt16(pv, 0, (short)TwainType.Int16); Marshal.WriteInt32(pv, 2, (int)sval); NativeMethods.GlobalUnlock(Handle); } ~TwainCapability() { Dispose(false); } public short Cap; public short ConType; public IntPtr Handle; public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (Handle != IntPtr.Zero) NativeMethods.GlobalFree(Handle); } } } 

所以,如果有人感兴趣我最终完全放弃了TWAIN – 我认为这根本不可能。

我做的是安装:

  • Cygwin (基本安装加gcc-coremakelibusb-win32包)
  • 的libusb-win32的
  • SANE 。

在完成整堆配置,制作和安装后,我终于能够从Cygwin提示符发出此命令:

 scanimage -t 30 -y 30 --mode Color --depth 8 --resolution 1200 --sharpness 2 --format=tiff --source TPU8x10 > out.tiff 

并且你会相信它out.tiff宽阔而锋利,比TWAIN更好。

所以,这是一个我知道的可怕的kludge,但我没有一大堆选项(它必须是一个Windows,胖客户端应用程序在连接扫描仪的机器上运行),所以我只是启动它:

 c:\cygwin\bin\bash.exe --login -c "scanimage -t 30 -y 30 --mode Color --depth 8 --resolution 1200 --sharpness 2 --format=tiff --source TPU8x10 > ~/out.tiff" 

通过.NET应用程序中的进程 ,当它返回时,我将文件加载到Bitmap中并继续进行,好像刚刚发生了什么怪异(意味着应用程序现在有一大堆额外的先决条件和繁琐的配置步骤,但是,嗯, meh,起诉我)。