Get image as Image Class with twain in c#

牧云@^-^@ 提交于 2019-12-13 15:03:21

问题


I can connect and get images from my device with twaindotnet. But I want to handle the images as Image class. When I try something like this:

    ...
  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;                          
       }                    
    ...

I'm getting an error as "Error:Generic Error Occured in GDI+" on the line ,

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

So where am I wrong? How can I get as an Image the image?


回答1:


I too found out that calling Image.FromHbitmap is not enough.

I had a look in the TwainDotNet library you mentioned and there I found the BitmapRenderer class.

Pulling out just the relevant bit it is easy enough to use that to create a simple static method that you can pass in the IntPtr you get from TWAIN (in your case your img variable) and convert it to a Bitmap. You, therefore, call it like so:

Image r = TwainBitmapConvertor.ToBitmap(img);

and here is the code (it only works on x86 and needs tidying but it does the job):

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:


Assuming that tw.TransferPictures() returns an array of bitmap handles, then change Image r = ... to:

      Image r = Image.FromHbitmap(img);

The second argument to FromHbitmap is a handle to a GDI palette, which I doubt you have.



来源:https://stackoverflow.com/questions/6131002/get-image-as-image-class-with-twain-in-c-sharp

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!