【问题标题】:Get image as Image Class with twain in c#在 c# 中使用 twain 将图像作为图像类获取
【发布时间】:2011-05-25 21:12:57
【问题描述】:

我可以使用twaindotnet 连接并从我的设备获取图像。但我想将图像处理为Image 类。当我尝试这样的事情时:

    ...
  ArrayList pics = tw.TransferPictures();
  EndingScan();
  tw.CloseSrc();

  if(pics.Count > 0)  {                     
  IntPtr img = (IntPtr) pics[ 0 ];
  PicForm newpic = new PicForm( img );
  Image r = Image.FromHbitmap(img, this.Handle);
  picturebox.Image = r;                          
       }                    
    ...

我收到一条错误消息,即“错误:GDI+ 中发生通用错误”,

Image r = Image.FromHbitmap(img, this.Handle);

那么我哪里错了?如何将图像作为图像获取?

【问题讨论】:

    标签: c# image twain


    【解决方案1】:

    我也发现打电话给Image.FromHbitmap是不够的。

    我查看了您提到的TwainDotNet 库,在那里我找到了BitmapRenderer 类。

    只提取相关位,很容易使用它来创建一个简单的静态方法,您可以传入从 TWAIN 获得的 IntPtr(在您的情况下是您的 img 变量)并将其转换为 @987654323 @。因此,您可以这样称呼它:

    Image r = TwainBitmapConvertor.ToBitmap(img);
    

    这是代码(它只适用于 x86,需要整理,但它确实可以完成工作):

    public 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;
        }
    
        [DllImport("gdi32.dll", ExactSpelling = true)]
        private 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("kernel32.dll", ExactSpelling = true)]
        private static extern IntPtr GlobalLock(IntPtr handle);
    
        [DllImport("kernel32.dll", ExactSpelling = true)]
        private static extern bool GlobalUnlock(IntPtr handle);
    
        [DllImport("kernel32.dll", ExactSpelling = true)]
        private static extern IntPtr GlobalFree(IntPtr handle);
    
        public static Bitmap ToBitmap(IntPtr dibHandle)
        {
            var bitmapPointer = 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
            Debug.Assert(Marshal.SizeOf(typeof(IntPtr)) == 4);
    
            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);
    
            Bitmap bitmap = new Bitmap(rectangle.Width, rectangle.Height);
    
            using (Graphics graphics = Graphics.FromImage(bitmap))
            {
                IntPtr hdc = graphics.GetHdc();
    
                try
                {
                    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));
    
            GlobalUnlock(dibHandle);
            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);
        }
    }
    

    【讨论】:

    • 我目前正在使用此解决方案,但生成的位图有错误。其中一些是颠倒的。有什么想法吗?
    【解决方案2】:

    假设tw.TransferPictures()返回一个位图句柄数组,那么将Image r = ...改为:

          Image r = Image.FromHbitmap(img);
    

    FromHbitmap 的第二个参数是 GDI 调色板的句柄,我怀疑你有。

    【讨论】:

    • 但是有一种重载方法,只接受一个参数。我可以使用什么作为 GDI 调色板?抱歉,我对这个标题太业余了。
    • 尝试使用一个参数的方法!你没有 GDI 调色板,所以不用担心。
    猜你喜欢
    • 2015-05-02
    • 2014-05-21
    • 2013-08-16
    • 1970-01-01
    • 2013-03-28
    • 1970-01-01
    • 1970-01-01
    • 2022-01-02
    • 2016-12-26
    相关资源
    最近更新 更多