Jump to content

HowTo: Making Paint.NET support TWAIN


dN!3L

Recommended Posts

Hi,

my scanner doesn't support WIA, so I made PDN support TWAIN devices. Some of the PDN users miss this function, so here is my code (the PDN source code has to be changed and recompiled):

overview:

1. create TwainLib class

2. create TwainSource class

3. add new menu item

4. implement menu item click logic

Link to comment
Share on other sites

1. create TwainLib class

First you have to add an new *.cs-file to your solution. The project "SystemLayer" contains the base scanning features, so I add it to this project. So add there a new *.cs-File, name it "TwainLib.cs" and copy the following code into it:

/////////////////////////////////////////////////////////////////////////////////
// 
// Source:	http://www.codeproject.com/dotnet/twaindotnet.asp
//			by Thomas Scheidegger
//			(public domain)
//
//
/////////////////////////////////////////////////////////////////////////////////


using System;
using System.Collections;
using System.Runtime.InteropServices;
using System.Windows.Forms;



namespace TwainLib
{
public enum TwainCommand
{
	Not=-1,
	Null=0,
	TransferReady=1,
	CloseRequest=2,
	CloseOk=3,
	DeviceEvent=4
}


public class Twain
{
	private const short CountryUSA		= 1;
	private const short LanguageUSA		= 13;

	public Twain()
	{
		appid = new TwIdentity();
		appid.Id				= IntPtr.Zero;
		appid.Version.MajorNum	= 1;
		appid.Version.MinorNum	= 1;
		appid.Version.Language	= LanguageUSA;
		appid.Version.Country	= CountryUSA;
		appid.Version.Info		= "Hack 1";
		appid.ProtocolMajor		= TwProtocol.Major;
		appid.ProtocolMinor		= TwProtocol.Minor;
		appid.SupportedGroups	= (int)(TwDG.Image | TwDG.Control);
		appid.Manufacturer		= "NETMaster";
		appid.ProductFamily		= "Freeware";
		appid.ProductName		= "Hack";

		srcds = new TwIdentity();
		srcds.Id = IntPtr.Zero;

		evtmsg.EventPtr = Marshal.AllocHGlobal(Marshal.SizeOf(winmsg));
	}

	~Twain()
	{
		Marshal.FreeHGlobal(evtmsg.EventPtr);
	}




	public void Init(IntPtr hwndp)
	{
		Finish();
		TwRC rc = DSMparent(appid,IntPtr.Zero,TwDG.Control,TwDAT.Parent,TwMSG.OpenDSM,ref hwndp);

		if (rc == TwRC.Success)
		{
			rc = DSMident(appid,IntPtr.Zero,TwDG.Control,TwDAT.Identity,TwMSG.GetDefault,srcds);
			if (rc == TwRC.Success)
				hwnd = hwndp;
			else
				rc = DSMparent(appid,IntPtr.Zero,TwDG.Control,TwDAT.Parent,TwMSG.CloseDSM,ref hwndp);
		}
	}



	public void Select()
	{
		TwRC rc;
		CloseSrc();
		if (appid.Id == IntPtr.Zero)
		{
			Init(hwnd);
			if (appid.Id == IntPtr.Zero)
				return;
		}

		rc = DSMident(appid,IntPtr.Zero,TwDG.Control,TwDAT.Identity,TwMSG.UserSelect,srcds);
	}



	public void Acquire()
	{
		TwRC rc;
		CloseSrc();
		if (appid.Id == IntPtr.Zero)
		{
			Init(hwnd);
			if (appid.Id == IntPtr.Zero)
				return;
		}
		rc = DSMident(appid,IntPtr.Zero,TwDG.Control,TwDAT.Identity,TwMSG.OpenDS,srcds);
		if (rc != TwRC.Success)
			return;

		TwCapability cap = new TwCapability(TwCap.XferCount,1);
		rc = DScap(appid,srcds,TwDG.Control,TwDAT.Capability,TwMSG.Set,cap);
		if (rc != TwRC.Success)
		{
			CloseSrc();
			return;
		}

		TwUserInterface guif = new TwUserInterface();
		guif.ShowUI = 1;
		guif.ModalUI = 1;
		guif.ParentHand = hwnd;
		rc = DSuserif(appid,srcds,TwDG.Control,TwDAT.UserInterface,TwMSG.EnableDS,guif);
		if (rc != TwRC.Success)
		{
			CloseSrc();
			return;
		}
	}



	public ArrayList TransferPictures()
	{
		ArrayList pics = new ArrayList();
		if (srcds.Id == IntPtr.Zero)
			return pics;

		TwRC rc;
		IntPtr hbitmap = IntPtr.Zero;
		TwPendingXfers pxfr = new TwPendingXfers();

		do
		{
			pxfr.Count = 0;
			hbitmap = IntPtr.Zero;

			TwImageInfo iinf = new TwImageInfo();
			rc = DSiinf(appid,srcds,TwDG.Image,TwDAT.ImageInfo,TwMSG.Get,iinf);
			if (rc != TwRC.Success)
			{
				CloseSrc();
				return pics;
			}

			rc = DSixfer(appid,srcds,TwDG.Image,TwDAT.ImageNativeXfer,TwMSG.Get,ref hbitmap);
			if (rc != TwRC.XferDone)
			{
				CloseSrc();
				return pics;
			}

			rc = DSpxfer(appid,srcds,TwDG.Control,TwDAT.PendingXfers,TwMSG.EndXfer,pxfr);
			if (rc != TwRC.Success)
			{
				CloseSrc();
				return pics;
			}

			pics.Add(hbitmap);
		}
		while (pxfr.Count != 0);

		rc = DSpxfer(appid,srcds,TwDG.Control,TwDAT.PendingXfers,TwMSG.Reset,pxfr);
		return pics;
	}



	public TwainCommand PassMessage(ref Message m)
	{
		if (srcds.Id == IntPtr.Zero)
			return TwainCommand.Not;

		int pos = GetMessagePos();

		winmsg.hwnd		= m.HWnd;
		winmsg.message	= m.Msg;
		winmsg.wParam	= m.WParam;
		winmsg.lParam	= m.LParam;
		winmsg.time		= GetMessageTime();

		unchecked
		{
			winmsg.x = (short)pos;
			winmsg.y = (short)(pos >> 16);
		}

		Marshal.StructureToPtr(winmsg,evtmsg.EventPtr,false);
		evtmsg.Message = 0;
		TwRC rc = DSevent(appid,srcds,TwDG.Control,TwDAT.Event,TwMSG.ProcessEvent,ref evtmsg);
		if (rc == TwRC.NotDSEvent)
			return TwainCommand.Not;
		if (evtmsg.Message == (short)TwMSG.XFerReady)
			return TwainCommand.TransferReady;
		if (evtmsg.Message == (short)TwMSG.CloseDSReq)
			return TwainCommand.CloseRequest;
		if (evtmsg.Message == (short)TwMSG.CloseDSOK)
			return TwainCommand.CloseOk;
		if (evtmsg.Message == (short)TwMSG.DeviceEvent)
			return TwainCommand.DeviceEvent;


		return TwainCommand.Null;
	}



	public void CloseSrc()
	{
		TwRC rc;
		if (srcds.Id != IntPtr.Zero)
		{
			TwUserInterface guif = new TwUserInterface();
			rc = DSuserif(appid,srcds,TwDG.Control,TwDAT.UserInterface,TwMSG.DisableDS,guif);
			rc = DSMident(appid,IntPtr.Zero,TwDG.Control,TwDAT.Identity,TwMSG.CloseDS,srcds);
		}
	}



	public void Finish()
	{
		TwRC rc;
		CloseSrc();
		if (appid.Id != IntPtr.Zero)
			rc = DSMparent(appid,IntPtr.Zero,TwDG.Control,TwDAT.Parent,TwMSG.CloseDSM,ref hwnd);
		appid.Id = IntPtr.Zero;
	}



	internal IntPtr hwnd;
	private TwIdentity appid;
	private TwIdentity srcds;
	private TwEvent evtmsg;
	private WINMSG winmsg;



	// ------ DSM entry point DAT_ variants:
	[DllImport("twain_32.dll",EntryPoint="#1")]
	private static extern TwRC DSMparent([in,Out] TwIdentity origin,IntPtr zeroptr,TwDG dg,TwDAT dat,TwMSG msg,ref IntPtr refptr);

	[DllImport("twain_32.dll",EntryPoint="#1")]
	private static extern TwRC DSMident([in,Out] TwIdentity origin,IntPtr zeroptr,TwDG dg,TwDAT dat,TwMSG msg,[in,Out] TwIdentity idds);

	[DllImport("twain_32.dll",EntryPoint="#1")]
	private static extern TwRC DSMstatus([in,Out] TwIdentity origin,IntPtr zeroptr,TwDG dg,TwDAT dat,TwMSG msg,[in,Out] TwStatus dsmstat);


	// ------ DSM entry point DAT_ variants to DS:
	[DllImport("twain_32.dll",EntryPoint="#1")]
	private static extern TwRC DSuserif([in,Out] TwIdentity origin,[in,Out] TwIdentity dest,TwDG dg,TwDAT dat,TwMSG msg,TwUserInterface guif);

	[DllImport("twain_32.dll",EntryPoint="#1")]
	private static extern TwRC DSevent([in,Out] TwIdentity origin,[in,Out] TwIdentity dest,TwDG dg,TwDAT dat,TwMSG msg,ref TwEvent evt);

	[DllImport("twain_32.dll",EntryPoint="#1")]
	private static extern TwRC DSstatus([in,Out] TwIdentity origin,[in] TwIdentity dest,TwDG dg,TwDAT dat,TwMSG msg,[in,Out] TwStatus dsmstat);

	[DllImport("twain_32.dll",EntryPoint="#1")]
	private static extern TwRC DScap([in,Out] TwIdentity origin,[in] TwIdentity dest,TwDG dg,TwDAT dat,TwMSG msg,[in,Out] TwCapability capa);

	[DllImport("twain_32.dll",EntryPoint="#1")]
	private static extern TwRC DSiinf([in,Out] TwIdentity origin,[in] TwIdentity dest,TwDG dg,TwDAT dat,TwMSG msg,[in,Out] TwImageInfo imginf);

	[DllImport("twain_32.dll",EntryPoint="#1")]
	private static extern TwRC DSixfer([in,Out] TwIdentity origin,[in] TwIdentity dest,TwDG dg,TwDAT dat,TwMSG msg,ref IntPtr hbitmap);

	[DllImport("twain_32.dll",EntryPoint="#1")]
	private static extern TwRC DSpxfer([in,Out] TwIdentity origin,[in] TwIdentity dest,TwDG dg,TwDAT dat,TwMSG msg,[in,Out] TwPendingXfers pxfr);


	[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("user32.dll",ExactSpelling=true)]
	private static extern int GetMessagePos();
	[DllImport("user32.dll",ExactSpelling=true)]
	private static extern int GetMessageTime();


	[DllImport("gdi32.dll",ExactSpelling=true)]
	private static extern int GetDeviceCaps(IntPtr hDC,int nIndex);

	[DllImport("gdi32.dll",CharSet=CharSet.Auto)]
	private static extern IntPtr CreateDC(string szdriver,string szdevice,string szoutput,IntPtr devmode);

	[DllImport("gdi32.dll",ExactSpelling=true)]
	private static extern bool DeleteDC(IntPtr hdc);




	public static int ScreenBitDepth
	{
		get
		{
			IntPtr screenDC = CreateDC("DISPLAY",null,null,IntPtr.Zero);
			int bitDepth = GetDeviceCaps(screenDC,12);
			bitDepth *= GetDeviceCaps(screenDC,14);
			DeleteDC(screenDC);
			return bitDepth;
		}
	}


	[structLayout(LayoutKind.Sequential,Pack=4)]
	internal struct WINMSG
	{
		public IntPtr hwnd;
		public int message;
		public IntPtr wParam;
		public IntPtr lParam;
		public int time;
		public int x;
		public int y;
	}
} // class Twain



public class TwProtocol
{									// TWON_PROTOCOL...
	public const short Major	= 1;
	public const short Minor	= 9;
}



[Flags]
internal enum TwDG : short
{									// DG_.....
	Control=0x0001,
	Image=0x0002,
	Audio=0x0004
}



internal enum TwDAT : short
{									// DAT_....
	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 TwMSG : short
{									// MSG_.....
	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
}



internal enum TwRC : short
{									// TWRC_....
	Success=0x0000,
	Failure=0x0001,
	CheckStatus=0x0002,
	Cancel=0x0003,
	DSEvent=0x0004,
	NotDSEvent=0x0005,
	XferDone=0x0006,
	EndOfList=0x0007,
	InfoNotSupported=0x0008,
	DataNotAvailable=0x0009
}



internal enum TwCC : short
{									// TWCC_....
	Success=0x0000,
	Bummer=0x0001,
	LowMemory=0x0002,
	NoDS=0x0003,
	MaxConnections=0x0004,
	OperationError=0x0005,
	BadCap=0x0006,
	BadProtocol=0x0009,
	BadValue=0x000a,
	SeqError=0x000b,
	BadDest=0x000c,
	CapUnsupported=0x000d,
	CapBadOperation=0x000e,
	CapSeqError=0x000f,
	Denied=0x0010,
	FileExists=0x0011,
	FileNotFound=0x0012,
	NotEmpty=0x0013,
	PaperJam=0x0014,
	PaperDoubleFeed=0x0015,
	FileWriteError=0x0016,
	CheckDeviceOnline=0x0017
}



internal enum TwOn : short
{									// TWON_....
	Array=0x0003,
	Enum=0x0004,
	One=0x0005,
	Range=0x0006,
	DontCare=-1
}



internal enum TwType : short
{									// TWTY_....
	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
}



internal enum TwCap : short
{
	XferCount=0x0001,			// CAP_XFERCOUNT
	ICompression=0x0100,			// ICAP_...
	IPixelType=0x0101,
	IUnits=0x0102,
	IXferMech=0x0103
}



// ------------------- STRUCTS --------------------------------------------



[structLayout(LayoutKind.Sequential,Pack=2,CharSet=CharSet.Ansi)]
internal class TwIdentity
{									// TW_IDENTITY
	public IntPtr Id;
	public TwVersion 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;
}



[structLayout(LayoutKind.Sequential,Pack=2,CharSet=CharSet.Ansi)]
internal struct TwVersion
{									// TW_VERSION
	public short MajorNum;
	public short MinorNum;
	public short Language;
	public short Country;
	[MarshalAs(UnmanagedType.ByValTStr,SizeConst=34)]
	public string Info;
}



[structLayout(LayoutKind.Sequential,Pack=2)]
internal class TwUserInterface
{									// TW_USERINTERFACE
	public short ShowUI;				// bool is strictly 32 bit, so use short
	public short ModalUI;
	public IntPtr ParentHand;
}



[structLayout(LayoutKind.Sequential,Pack=2)]
internal class TwStatus
{									// TW_STATUS
	public short ConditionCode;		// TwCC
	public short Reserved;
}



[structLayout(LayoutKind.Sequential,Pack=2)]
internal struct TwEvent
{									// TW_EVENT
	public IntPtr EventPtr;
	public short Message;
}



[structLayout(LayoutKind.Sequential,Pack=2)]
internal class TwImageInfo
{									// TW_IMAGEINFO
	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 TwPendingXfers
{									// TW_PENDINGXFERS
	public short Count;
	public int EOJ;
}



[structLayout(LayoutKind.Sequential,Pack=2)]
internal struct TwFix32
{												// TW_FIX32
	public short Whole;
	public ushort Frac;

	public float ToFloat()
	{
		return (float)Whole + ((float)Frac /65536.0f);
	}
	public void FromFloat(float f)
	{
		int i = (int)((f * 65536.0f) + 0.5f);
		Whole = (short)(i >> 16);
		Frac = (ushort)(i & 0x0000ffff);
	}
}



[structLayout(LayoutKind.Sequential,Pack=2)]
internal class TwCapability
{									// TW_CAPABILITY
	public TwCapability(TwCap cap)
	{
		Cap = (short)cap;
		ConType = -1;
	}
	public TwCapability(TwCap cap,short sval)
	{
		Cap = (short)cap;
		ConType = (short)TwOn.One;
		Handle = Twain.GlobalAlloc(0x42,6);
		IntPtr pv = Twain.GlobalLock(Handle);
		Marshal.WriteInt16(pv,0,(short)TwType.Int16);
		Marshal.WriteInt32(pv,2,(int)sval);
		Twain.GlobalUnlock(Handle);
	}
	~TwCapability()
	{
		if (Handle != IntPtr.Zero)
			Twain.GlobalFree(Handle);
	}
	public short Cap;
	public short ConType;
	public IntPtr Handle;
}


} // namespace TwainLib

Link to comment
Share on other sites

2. create TwainSource class

The same procedure as in 1., but name it "TwainSource.cs" and take the following code:

/////////////////////////////////////////////////////////////////////////////////
// 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;
using System.Windows.Forms;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Threading;

using TwainLib;


namespace PaintDotNet.SystemLayer
{
/// 
/// a simple API for TWAIN device
/// 
public class TwainSource : IMessageFilter,IDisposable
{
	/// 
	/// constructor
	/// 
	/// parent window handle
	public TwainSource(IntPtr hwndp)
	{
		twain = new Twain();
		twain.Init(hwndp);
	}


	/// 
	/// clear ressources
	/// 
	public void Dispose()
	{
		twain.Finish();
	}



	private bool messageFilterIsActive;
	private TwainLib.Twain twain;


	/// 
	/// all aquired pictures from TWAIN device
	/// 
	public IList ScannedImages = new List();


	/// 
	/// TWAIN device begins to acquire images
	/// 
	public event EventHandler TransferStarted;


	/// 
	/// TWAIN device finished acquire images
	/// 
	public event EventHandler TransferFinished;


	/// 
	/// displays a form for selecting the TWAIN device
	/// 
	public void SelectTwainSource()
	{
		twain.Select();
	}


	/// 
	/// displays the UI of the TWAIN device
	/// 
	public void ShowTwainUi()
	{
		if (!messageFilterIsActive)
		{
			messageFilterIsActive = true;
			ScannedImages.Clear();
			Application.AddMessageFilter(this);
		}
		twain.Acquire();
	}


	/// 
	/// stop listening for TWAIN device results
	/// 
	public void EndingScan()
	{
		if (messageFilterIsActive)
		{
			Application.RemoveMessageFilter(this);
			messageFilterIsActive = false;

			if (TransferFinished!=null)
				TransferFinished(this,null);
		}
	}


	/// 
	/// receives messages and handles TWAIN device messages
	/// 
	/// the message
	/// message is handled
	public bool PreFilterMessage(ref System.Windows.Forms.Message m)
	{
		TwainCommand twainCommand = twain.PassMessage(ref m);
		if (twainCommand==TwainCommand.Not)
			return false;

		switch (twainCommand)
		{
			case TwainCommand.CloseRequest:
				{
					EndingScan();
					twain.CloseSrc();
					break;
				}
			case TwainCommand.CloseOk:
				{
					EndingScan();
					twain.CloseSrc();
					break;
				}
			case TwainCommand.DeviceEvent:
				{
					break;
				}
			case TwainCommand.TransferReady:
				{
					if (TransferStarted!=null)
						TransferStarted(this,null);

					ArrayList pics = twain.TransferPictures();

					foreach (IntPtr img in pics)
						ScannedImages.Add(bitmapFromDIB(img));

					EndingScan();
					twain.CloseSrc();
				}
				break;

			case TwainCommand.Null:
				{
					twainCommandNullCount++;

					if (twainCommandNullCount>25)
					{
						twainCommandNullCount = 0;
						EndingScan();
						twain.CloseSrc();
					}
					break;
				}
		}

		return true;
	}
	// hack: TwainCommand.Null is sended continuously after TWAIN device is not available or when once preview is done
	private int twainCommandNullCount = 0;


	/// 
	/// converts the TWAIN device result to .NET Bitmap
	/// 
	/// pointer to aquired image
	/// TWAIN device as .NET Bitmap
	private Bitmap bitmapFromDIB(IntPtr dibhand)
	{
		IntPtr bmpptr = GlobalLock(dibhand);
		IntPtr pixptr = GetPixelInfo(bmpptr);

		IntPtr pBmp = IntPtr.Zero;
		int status = GdipCreateBitmapFromGdiDib(bmpptr,pixptr,ref pBmp);

		if ((status == 0) && (pBmp != IntPtr.Zero))
		{
			MethodInfo mi = typeof(Bitmap).GetMethod("FromGDIplus",BindingFlags.Static | BindingFlags.NonPublic);
			if (mi == null)
				return null;

			Bitmap result = new Bitmap(mi.Invoke(null,new object[] { pBmp }) as Bitmap);

			GlobalFree(dibhand);
			dibhand = IntPtr.Zero;

			return result;
		}
		else
			return null;
	}


	private IntPtr GetPixelInfo(IntPtr bmpptr)
	{
		BITMAPINFOHEADER bmi = new BITMAPINFOHEADER();
		Marshal.PtrToStructure(bmpptr,bmi);

		Rectangle bmprect = new Rectangle(0,0,bmi.biWidth,bmi.biHeight);

		if (bmi.biSizeImage == 0)
			bmi.biSizeImage = ((((bmi.biWidth * bmi.biBitCount) + 31) & ~31) >> 3) * bmi.biHeight;

		int p = bmi.biClrUsed;
		if ((p == 0) && (bmi.biBitCount <= 8))
			p = 1 << bmi.biBitCount;
		p = (p * 4) + bmi.biSize + (int)bmpptr;
		return (IntPtr)p;
	}


	[DllImport("gdiplus.dll",ExactSpelling=true)]
	private static extern int GdipCreateBitmapFromGdiDib(IntPtr bminfo,IntPtr pixdat,ref IntPtr image);

	[DllImport("kernel32.dll",ExactSpelling=true)]
	private static extern IntPtr GlobalLock(IntPtr handle);

	[DllImport("kernel32.dll",ExactSpelling=true)]
	private static extern IntPtr GlobalFree(IntPtr handle);

	[structLayout(LayoutKind.Sequential,Pack=2)]
	private class BITMAPINFOHEADER
	{
		public int biSize=0;
		public int biWidth=0;
		public int biHeight=0;
		public short biPlanes=0;
		public short biBitCount=0;
		public int biCompression=0;
		public int biSizeImage=0;
		public int biXPelsPerMeter=0;
		public int biYPelsPerMeter=0;
		public int biClrUsed=0;
		public int biClrImportant=0;
	}
}
}

Link to comment
Share on other sites

3. add new menu item

Now you have to add a new menu item to the main menu. Open "MainForm.cs" (project "paintdotnet"). Search the code between the following -Tags and replace it with the code between the -Tags.

// 
// private System.Windows.Forms.ToolStripMenuItem menuFileAcquireFromScannerOrCamera;
// 
// 
private System.Windows.Forms.ToolStripMenuItem menuFileAcquireFromScannerOrCameraWia;
private System.Windows.Forms.ToolStripMenuItem menuFileAcquireFromScannerOrCameraTwain;
// 

// 
//this.menuFileAcquireFromScannerOrCamera = new System.Windows.Forms.ToolStripMenuItem();
// 
// 
this.menuFileAcquireFromScannerOrCameraWia = new System.Windows.Forms.ToolStripMenuItem();
this.menuFileAcquireFromScannerOrCameraTwain = new System.Windows.Forms.ToolStripMenuItem();
// 

// 
// menuFileAcquire
// 
this.menuFileAcquire.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
																			this.menuFileAcquireFromClipboard,
																			// 
																			// this.menuFileAcquireFromScannerOrCamera
																			// 
																			// 
																				this.menuFileAcquireFromScannerOrCameraWia,
																				this.menuFileAcquireFromScannerOrCameraTwain
																			// 
																				});

// 
// 
// menuFileAcquireFromScannerOrCamera
// 
//this.menuFileAcquireFromScannerOrCamera.Click += new System.EventHandler(this.menuFileAcquireFromScannerOrCamera_Click);
// 
// 
// 
// menuFileAcquireFromScannerOrCameraWia
// 
this.menuFileAcquireFromScannerOrCameraWia.Click += new System.EventHandler(this.menuFileAcquireFromScannerOrCameraWia_Click);
// 
// menuFileAcquireFromScannerOrCameraTwain
// 
this.menuFileAcquireFromScannerOrCameraTwain.Click += new System.EventHandler(this.menuFileAcquireFromScannerOrCameraTwain_Click);
// 

// 
// this.menuFileAcquireFromScannerOrCamera.Text = PdnResources.GetString("MainForm.Menu.File.Acquire.FromScannerOrCamera.Text");
// 
// 
this.menuFileAcquireFromScannerOrCameraWia.Text = PdnResources.GetString("MainForm.Menu.File.Acquire.FromScannerOrCamera.Text").Replace("..."," (WIA)...");
this.menuFileAcquireFromScannerOrCameraTwain.Text = PdnResources.GetString("MainForm.Menu.File.Acquire.FromScannerOrCamera.Text").Replace("..."," (TWAIN)...");
// 

// 
// private void menuFileAcquireFromScannerOrCamera_Click(object sender,System.EventArgs e)
// 
// 
private void menuFileAcquireFromScannerOrCameraWia_Click(object sender,System.EventArgs e)
// 

// 
// menuFileAcquireFromScannerOrCamera.Enabled = scannerEnabled;
// 
// 
menuFileAcquireFromScannerOrCameraWia.Enabled = scannerEnabled;
// 

Link to comment
Share on other sites

4. implement menu item click logic

And finally you have to add the menu click logic for TWAIN acquirering. Add this code to "MainForm.cs":

private void menuFileAcquireFromScannerOrCameraTwain_Click(object sender,System.EventArgs e)
{
using (new WaitCursorChanger(this))
{
	// initialize TwainSource
	if (twainSource==null)
	{
		twainSource = new TwainSource(this.Handle);
		twainSource.TransferFinished += new EventHandler(twainSource_TransferFinished);
	}

	// select source and show Twain-UI
	twainSource.SelectTwainSource();
	twainSource.ShowTwainUi();
}
}

// the TWAIN supporting class
TwainSource twainSource = null;



/// 
/// when TWAIN finished the transfer, put results into workspace
/// 
void twainSource_TransferFinished(object sender,EventArgs e)
{
using (new WaitCursorChanger(this))
{
	string errorText = null;

	try
	{
		foreach (Bitmap bitmap in twainSource.ScannedImages)
		{
			// first ask for save if needed
			if (workspace.Document.Dirty)
			{
				switch (AskForSave())
				{
					case DialogResult.Yes:
						if (!DoSave())
						{
							return;
						}

						break;

					case DialogResult.No:
						break;

					case DialogResult.Cancel:
						return;
				}
			}

			// create new document from scanned image...
			Document document;
			try
			{
				document = Document.FromImage(bitmap);
			}
			catch (OutOfMemoryException)
			{
				errorText = PdnResources.GetString("MainForm.LoadDocument.Error.OutOfMemoryException");
				throw;
			}

			// ... and replace current document with it
			try
			{
				workspace.SetDocument(document);
			}
			catch (OutOfMemoryException)
			{
				errorText = PdnResources.GetString("MainForm.LoadDocument.Error.OutOfMemoryException");
				throw;
			}

			document = null;
			workspace.SetDocumentSaveOptions(null,null,null);
			workspace.History.ClearAll();
			HistoryAction newHA = new NullHistoryAction(PdnResources.GetString("AcquireImageAction.Name"),this.AddNewLayerIcon);
			workspace.History.PushNewAction(newHA);
		}
	}
	catch (Exception)
	{
		if (errorText != null)
		{
			Utility.ErrorBox(this,errorText);
		}
		else
		{
			throw;
		}
	}
}
}

Link to comment
Share on other sites

  • 1 year later...

No necroposting.

 

The Doctor: There was a goblin, or a trickster, or a warrior... A nameless, terrible thing, soaked in the blood of a billion galaxies. The most feared being in all the cosmos. And nothing could stop it, or hold it, or reason with it. One day it would just drop out of the sky and tear down your world.
Amy: But how did it end up in there?
The Doctor: You know fairy tales. A good wizard tricked it.
River Song: I hate good wizards in fairy tales; they always turn out to be him.

Link to comment
Share on other sites

Guest
This topic is now closed to further replies.
×
×
  • Create New...