4

我正在编写一个需要在 .net 中扫描的应用程序(c#版本4.0,Visual Studio 2010)。我正在使用TWAINAPI 进行扫描,但布局功能有问题。以下代码在 a Microtek i800、 aCanoScan 9000F和 a上运行得非常好,Microtek Artix Scan F2但是当我在Epson Perfection V700上运行它时,会发生一些非常奇怪的事情。

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

所以我的问题是...

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

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


这是代码(它是一个带有单个按钮的 1 窗体 windows 窗体应用程序的代码):

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<Bitmap> Scan(TwainIdentity appid, 
                                         TwainIdentity scanner)
        {
            var pictures = new List<Bitmap>();          

            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);
        }
    }
}
4

1 回答 1

1

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

我所做的是安装:

经过一大堆配置、制作和安装后,我终于能够从Cygwin提示符下发出这个命令:

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

你会相信它out.tiff宽而锐利,而且比我用TWAIN所能达到的要好得多。

所以,我知道这是一个可怕的问题,但我没有一大堆选择(它必须是一个 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 应用程序中的进程,当它返回时,我将文件加载到位图中并继续进行,就好像没有发生任何奇怪的事情一样(意味着应用程序现在有一大堆额外的先决条件和繁琐的配置步骤,但是,好吧,嗯,起诉我)。

于 2013-03-06T09:11:36.077 回答