|
Hi
I've some problems with configure the scan area. I use code wrote by cmchuan
[StructLayout(LayoutKind.Sequential, Pack = 2)]
internal struct TwFrame {
public int Left;
public int Top;
public int Right;
public int Bottom;
}
//set the scan area using a call like this
TwImageLayout layout = new TwImageLayout();
//Get the default layout
TwRC rc = DSilayout(appid, srcds, TwDG.Image, TwDAT.ImageLayout, TwMSG.Get, Layout);
Layout.Frame.Top = 0; //Set the top margin
Layout.Frame.Left = 0; //Set left margin
Layout.Frame.Right = 0; //Set right margin
Layout.Frame.Bottom = 0; //Set bottom margin
Layout.FrameNumber = 1;
Layout.PageNumber = 1;
Layout.DocumentNumber = 1;
rc = DSilayout(appid, srcds, TwDG.Image, TwDAT.ImageLayout, TwMSG.Set, layout);
TwStatus s = new TwStatus();
rc = DSstatus(appid, srcds, TwDG.Control, TwDAT.Status, TwMSG.Get, s);
if( rc != TwRC.Success )
{
CloseSrc();
return false;
}
I change margins but it's always scan all area. What should i do to scan small fragment?
|
|
|
|
|
I have post full VB.NET code in above.
|
|
|
|
|
Could You mark fragment responsible for selecting and setuping area?
Regards
alien250
|
|
|
|
|
One the things that I found difficult about developing my Twain application was that I often could not get the excellent code posted here to work. Often I would get 'success' returned from trying to set the dpi or the bitdepth or other capabilities but the effect was zero.
I have noticed that many others have the same problem. I finally went to the web site (http://www.twain.org/docs/Spec1_9_197.pdf) for Twain and actually read the document setting out the standards.
I was developing an Optical Mark Recognition application for which I had written an algorithm and was adding the Twain standard so I could scan and read forms. I needed to set the DPI, the bit depth and the resolution and tried using the code here to do so. I could scan but was unsuccessful in setting the different elements. The application would return 'success' but the final scan woull not reflect the changes.
It turns out that the capabilities of the scanner should be set in sequence according to the standard. For example, you have to set the pixel type before the bitdepth before the x and y resolution. This is strictly enforced on many systems, particularly on high end scanners like the Fujitsu I am using.
A system will return 'success' because you have made the right call but do nothing because you have not set the caps in the right order.
Following the changes in line with the Twain standard I have just successfully scanned and processed 500 forms consisting of a total of 3,000 pages.
Hopefully this will work for others.
Alan
'Nemo me impune Lacessit'
|
|
|
|
|
hello there, i saw ur article, it seems u r the person that can help.
i m making an application to scan multiple forms, 100 pages per minute using twain in black & white.
so far the application made scans only 1 page, i want to scan and save multiple pages to the directory i want. can u guide me what steps shall i perform in order to achieve that,
|
|
|
|
|
Did anyone find a way how to scan image directly without showing user interface of the source? Is that property related with CAP_AUTOSCAN capability, if so how i will set this capability to true using the interface above written by NetMaster.
I need ur helps...
|
|
|
|
|
The following is a function that populates an internal ArrayList(_Sources) of TwIdentity and returns number of sources found. You can then use this ArrayList to select the source of choice.
public int GetDataSources()
{
//ArrayList ds = new ArrayList();
_Sources = new ArrayList();
TwIdentity scanner = new TwIdentity();
TwIdentity defScanner = new TwIdentity();
CloseSrc();
if (appid.Id == IntPtr.Zero)
{
Init(hwnd);
if (appid.Id == IntPtr.Zero)
return _Sources.Count;
}
//Get the default
if (DSMident(appid, IntPtr.Zero, TwDG.Control, TwDAT.Identity, TwMSG.GetDefault, defScanner) != TwRC.Success)
return _Sources.Count;
if (DSMident(appid, IntPtr.Zero, TwDG.Control, TwDAT.Identity, TwMSG.GetFirst, scanner) == TwRC.Success)
{
//Select default data source
if (scanner.Id == defScanner.Id)
_SelectedSource = _Sources.Count;
_Sources.Add(scanner);
//Loop through and find all sources and add to array
scanner = new TwIdentity();
while (DSMident(appid, IntPtr.Zero, TwDG.Control, TwDAT.Identity, TwMSG.GetNext, scanner) == TwRC.Success)
{
//Select default data source
if (scanner.Id == defScanner.Id)
_SelectedSource = _Sources.Count;
_Sources.Add(scanner);
scanner = new TwIdentity();
}
}
return _Sources.Count;
}
To Select the desired Datasource you could to do the following:
public bool SelectSource(int SourceIndex)
{
//Select correct datasource
srcds = (TwIdentity)_Sources[SourceIndex];
//Close Datasource
CloseSrc();
//Invoke set command of datasource
rc = DSMident(appid, IntPtr.Zero, TwDG.Control, TwDAT.Identity, TwMSG.Set, srcds);
if (rc != TwRC.Success)
return false;
}
Hope that helps
|
|
|
|
|
hi ,,
I want to change the way to select source device and for that i have added a combobox in my application and to work with this i found your code which may help me but when i implemented it give some error.
1.what is "SelectedSource" in your code
2.SelectSource function error--not all code paths return a value.
but i have done some little modification
which give only one error that is "SelectedSource"
please help me which place i have to add this function and further procedure for implement this feature.
please help me
|
|
|
|
|
hello, i have download the code and learn many thing for it.
i want to change the scan UI in the code, but don't know TWAIN exactly.
i find the Acquire sub is very important, and some structure or Inherits some function from TWAIN will finish it.
thank you very much for your help
MSN: zhangjiuheng@hotmail.com
web: www.hengjiu.cc
MSN: zhangjiuheng@hotmail.com
web: www.hengjiu.cc
|
|
|
|
|
thank you for this great article
i want to handle scanner event like paperjam in my application but i dont know how to do this i tried some way like setting deviceevent capability
but it doesnt work and returnz sfailure message when im setting
please some body help me
|
|
|
|
|
Hi,
Is there any way to suppress the user interfaces from twain driver?
First, I want to handle the error while scanning, opening data source or closing data source. Is this can do by not showing UI?
Second is, while scanning, scanning process progressbar is pops up. Can we invisible this UI?
Urgent help needed!!
bg
|
|
|
|
|
|
|
thanks for the reference, I've moved that code to http://www.codeplex.com/openTwain as gotdotnet is closing.
|
|
|
|
|
This class extends what m@u had posted.
[SecurityPermission(SecurityAction.Assert, Flags=SecurityPermissionFlag.UnmanagedCode)]
[FileIOPermission(SecurityAction.Assert, Unrestricted=true)]
public class TwainManager : NativeWindow, IDisposable
{
[DllImport("kernel32.dll", ExactSpelling = true)]
internal static extern IntPtr GlobalLock(IntPtr handle);
[DllImport("kernel32.dll", ExactSpelling = true)]
internal static extern IntPtr GlobalFree(IntPtr handle);
private Twain _scanner;
private List<fileinfo> _files;
private TwainConfig _scannerConfig;
private bool _ready = false;
private byte[] _binaryImage;
public byte[] BinaryImage
{
get
{
return _binaryImage;
}
}
public bool Ready
{
get
{
return _ready;
}
}
public TwainManager()
{
_scannerConfig = TwainConfig.GetConfig();
CreateParams cp = new CreateParams();
cp.Parent = new IntPtr(-3);
//cp.ClassName = "Window";
cp.Caption = "";
this.CreateHandle(cp);
_scanner = new Twain();
_scanner.Init(Handle);
if (string.IsNullOrEmpty(_scannerConfig.ActiveDevice))
_scannerConfig.ActiveDevice = _scanner.ActiveDeviceName;
else
{
if (!_scanner.SelectByName(_scannerConfig.ActiveDevice))
{
_scanner.Init(Handle);
_scannerConfig.ActiveDevice = _scanner.ActiveDeviceName;
}
}
_scannerConfig.Save();
}
public bool SelectScanner()
{
_ready = _scanner.Select();
if (_ready)
{
_scannerConfig.ActiveDevice = _scanner.ActiveDeviceName;
_scannerConfig.Save();
}
return _ready;
}
private void AddScan()
{
if (_scanner.Acquire() != TwRC.Success)
{
EndScanning();
throw new Exception("Document could not be scanned");
}
}
public void Scan()
{
if (_ready)
{
_files = new List<fileinfo>();
_binaryImage = null;
if (_scanner.Acquire() != TwRC.Success)
{
EndScanning();
throw new Exception("Document could not be scanned");
}
}
else
{
if (SelectScanner())
Scan();
}
}
private void AnalyzeImage(IntPtr pic)
{
IntPtr bmpPtr = IntPtr.Zero;
IntPtr pixPtr = IntPtr.Zero;
string tempFile = Path.GetTempFileName().Replace(".tmp", ".tif");
try
{
if (pic.Equals(IntPtr.Zero))
{
EndScanning();
_scanner.CloseSrc();
return;
}
bmpPtr = GlobalLock(pic);
pixPtr = GetPixelInfo(bmpPtr);
GdiPlusLib.SaveDIBAs(tempFile, bmpPtr, pixPtr);
FileInfo fi = new FileInfo(tempFile);
if (fi.Exists)
_files.Add(fi);
}
catch (Exception ex)
{
throw ex;
}
}
private IntPtr GetPixelInfo(IntPtr bmpptr)
{
Rectangle bmprect = default(Rectangle);
BITMAPINFOHEADER bmi = new BITMAPINFOHEADER();
Marshal.PtrToStructure(bmpptr, bmi);
bmprect.X = bmprect.Y = 0;
bmprect.Width = bmi.biWidth;
bmprect.Height = 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;
}
protected override void WndProc(ref Message m)
{
if (_scanner != null)
{
TwainCommand cmd = _scanner.PassMessage(ref m);
if (cmd == TwainCommand.Not)
return;
switch (cmd)
{
case TwainCommand.CloseRequest:
EndScanning();
_scanner.CloseSrc();
break;
case TwainCommand.CloseOk:
EndScanning();
_scanner.CloseSrc();
break;
case TwainCommand.DeviceEvent:
break;
case TwainCommand.TransferReady:
ScanImage();
break;
}
}
base.WndProc(ref m);
}
private void ScanImage()
{
IntPtr pic = IntPtr.Zero;
try
{
pic = _scanner.TransferPicture();
AnalyzeImage(pic);
if (_scanner.HasMorePages)
ScanImage();
else
{
_scanner.CloseSrc();
if (DialogResult.No == MessageBox.Show(
"Would you like to add more pages?", "Continue Scanning?",
MessageBoxButtons.YesNo,
MessageBoxIcon.Question))
{
BuildTiff();
}
else
{
AddScan();
}
}
}
catch (Exception ex)
{
throw ex;
}
}
private void EndScanning()
{
}
private EncoderParameters GetEncoderParameters(EncoderValue SaveFlag, EncoderValue Compression)
{
EncoderParameters enParams = new EncoderParameters(2);
enParams.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.SaveFlag, (long)SaveFlag);
enParams.Param[1] = new EncoderParameter(System.Drawing.Imaging.Encoder.Compression, (long)Compression);
return enParams;
}
private ImageCodecInfo GetEncoderInfo(String mimeType)
{
ImageCodecInfo[] encoders;
encoders = ImageCodecInfo.GetImageEncoders();
for (int i = 0; i < encoders.Length; i++)
{
if (String.Compare(mimeType, encoders[i].MimeType, true) == 0)
{
return encoders[i];
}
}
return null;
}
private void BuildTiff()
{
string tiffPath = Path.GetTempFileName().Replace(".tmp", ".tif");
Bitmap b = null;
if (_files.Count > 0)
{
b = (Bitmap)Bitmap.FromFile(_files[0].FullName);
if (b.PixelFormat == PixelFormat.Format1bppIndexed)
b.Save(tiffPath, GetEncoderInfo("image/tiff"), GetEncoderParameters(EncoderValue.MultiFrame, EncoderValue.CompressionCCITT4));
else
b.Save(tiffPath, GetEncoderInfo("image/tiff"), GetEncoderParameters(EncoderValue.MultiFrame, EncoderValue.CompressionLZW));
for (int i = 1; i < _files.Count; i++)
{
Image image = Image.FromFile(_files[i].FullName);
if (image.PixelFormat == PixelFormat.Format1bppIndexed)
b.SaveAdd(image, GetEncoderParameters(EncoderValue.FrameDimensionPage, EncoderValue.CompressionCCITT4));
else
b.SaveAdd(image, GetEncoderParameters(EncoderValue.FrameDimensionPage, EncoderValue.CompressionLZW));
}
b.Dispose();
b = null;
}
else
throw new Exception("No document scanned.");
FileStream fs = new FileStream(tiffPath, FileMode.Open, FileAccess.Read);
_binaryImage = new Byte[fs.Length];
fs.Read(_binaryImage, 0, (int)fs.Length);
fs.Close();
fs.Dispose();
fs = null;
b = null;
if (_binaryImage == null || _binaryImage.Length < 1)
throw new Exception("No document could be scanned.");
}
#region IDisposable Member
public void Dispose()
{
try
{
if(_scanner != null)
_scanner.CloseSrc();
}
catch { }
_scanner = null;
}
#endregion
}
Breaking your theories
Sully
|
|
|
|
|
I have created a Class Library. I scan and save the image to a file. Then I read from the file to display in a picturebox. When I use the library in a form, it scans, saves image to a file and displays the image in the picturebox.
When I use the DLL (library) in a HTML page, it scans, but the (user specified) file is not created. Instead, it creates a file in TEMP called TwainDS.tif and then the program hangs.
Anyone have any idea why?
|
|
|
|
|
Interesting!
I am having a very similar scenario. My problem is that when I run the code from an ActiveX wrapper, the scanner never receives the command to scan. In other words, the PreFilterMessage never catches any message! I even tried with WndProc method, but no success. But when the code is ran from directly (running the .exe or debugging within Visual Studio), all works perfectly!
I assume it has something to do with the fact that the parent process (owner) is IE8... I am not sure...
Any ideas?
|
|
|
|
|
Hi,I have the same issue,any ideas for me?
Thanks advanced.
|
|
|
|
|
Hi!
I have a problem with this code(Twain Manager for .NET ActiveX)
What is TwainConfig?
Could you public or mail complete source of ActiveX decision?
Thanks.
Vasig
|
|
|
|
|
Hi,
I want to list available scanners in my own listbox, not in twain's gui. Becuse i want to use alias names of scanners.
Is there anyway to get scanner list shown in the SelctSource() dialog box?
Thanks.
bg
|
|
|
|
|
Hi
First of all, i really love that class
I needed to use Twain and didn't want to handle the Messages in the Main - Form.
here's how to do it:
<br />
public class ImageScannedEventArgs:EventArgs<br />
{<br />
private Bitmap image;<br />
public Bitmap Image<br />
{<br />
get<br />
{<br />
return image;<br />
}<br />
}<br />
public ImageScannedEventArgs(Bitmap Image)<br />
{<br />
image = Image;<br />
}<br />
}<br />
public delegate void ImageScannedEventHandler(object sender, ImageScannedEventArgs e);<br />
[StructLayout(LayoutKind.Sequential, Pack=2)]<br />
internal class BITMAPINFOHEADER<br />
{<br />
public int biSize;<br />
public int biWidth;<br />
public int biHeight;<br />
public short biPlanes;<br />
public short biBitCount;<br />
public int biCompression;<br />
public int biSizeImage;<br />
public int biXPelsPerMeter;<br />
public int biYPelsPerMeter;<br />
public int biClrUsed;<br />
public int biClrImportant;<br />
}<br />
public class TwainMan:NativeWindow,IDisposable<br />
{<br />
[DllImport("kernel32.dll", ExactSpelling=true)]<br />
internal static extern IntPtr GlobalLock( IntPtr handle );<br />
[DllImport("kernel32.dll", ExactSpelling=true)]<br />
internal static extern IntPtr GlobalFree( IntPtr handle );<br />
private Twain tw;<br />
private BITMAPINFOHEADER bmi;<br />
private Rectangle bmprect;<br />
private bool ready = false;<br />
public event ImageScannedEventHandler ImageScanned;<br />
public bool Ready<br />
{<br />
get<br />
{<br />
return ready;<br />
}<br />
}<br />
public TwainMan()<br />
{<br />
CreateParams cp = new CreateParams();<br />
cp.Parent = new IntPtr(-3);<br />
cp.Caption = "";<br />
this.CreateHandle(cp);<br />
tw = new Twain();<br />
tw.Init(Handle);<br />
}<br />
public void Select()<br />
{<br />
ready = tw.Select();<br />
}<br />
public void Scan()<br />
{<br />
if (ready)<br />
{<br />
tw.Acquire();<br />
}<br />
}<br />
protected IntPtr GetPixelInfo( IntPtr bmpptr )<br />
{<br />
bmi = new BITMAPINFOHEADER();<br />
Marshal.PtrToStructure( bmpptr, bmi );<br />
bmprect = Rectangle.Empty;<br />
bmprect.X = bmprect.Y = 0;<br />
bmprect.Width = bmi.biWidth;<br />
bmprect.Height = bmi.biHeight;<br />
<br />
if( bmi.biSizeImage == 0 )<br />
bmi.biSizeImage = ((((bmi.biWidth * bmi.biBitCount) + 31) & ~31) >> 3) * bmi.biHeight;<br />
<br />
int p = bmi.biClrUsed;<br />
if( (p == 0) && (bmi.biBitCount <= 8) )<br />
p = 1 << bmi.biBitCount;<br />
p = (p * 4) + bmi.biSize + (int) bmpptr;<br />
return (IntPtr) p;<br />
}<br />
protected virtual void onImageScanned(ImageScannedEventArgs e)<br />
{<br />
if (ImageScanned != null)<br />
{<br />
ImageScanned(this,e);<br />
}<br />
}<br />
protected override void WndProc(ref Message m)<br />
{<br />
if (tw != null)<br />
{<br />
TwainCommand cmd = tw.PassMessage( ref m );<br />
if( cmd != TwainCommand.Not )<br />
{<br />
switch( cmd )<br />
{<br />
case TwainCommand.CloseRequest:<br />
{<br />
tw.CloseSrc();<br />
ready = false;<br />
break;<br />
}<br />
case TwainCommand.CloseOk:<br />
{<br />
tw.CloseSrc();<br />
ready = false;<br />
break;<br />
}<br />
case TwainCommand.DeviceEvent:<br />
{<br />
break;<br />
}<br />
case TwainCommand.TransferReady:<br />
{<br />
ArrayList pics = tw.TransferPictures();<br />
tw.CloseSrc();<br />
for( int i = 0; i < pics.Count; i++ )<br />
{<br />
IntPtr img = (IntPtr) pics[ i ];<br />
IntPtr bmpt = GlobalLock(img);<br />
IntPtr pi = GetPixelInfo(bmpt);<br />
IntPtr imgH = IntPtr.Zero;<br />
int Ret = GdiPlusLib.Gdip.GdipCreateBitmapFromGdiDib(bmpt,pi,ref imgH);<br />
if (img != IntPtr.Zero)<br />
{<br />
Bitmap bmp = (Bitmap)typeof(Bitmap).InvokeMember("FromGDIplus", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.InvokeMethod, null, null, new object[] { imgH });<br />
onImageScanned(new ImageScannedEventArgs(bmp.Clone() as Bitmap));<br />
}<br />
}<br />
break;<br />
}<br />
}<br />
}<br />
}<br />
base.WndProc(ref m);<br />
}<br />
#region IDisposable Member<br />
<br />
public void Dispose()<br />
{<br />
try<br />
{<br />
tw.CloseSrc();<br />
}<br />
catch{}<br />
tw = null;<br />
}<br />
<br />
#endregion<br />
}<br />
now i only have to create an instance of TwainMan and it does the Messagehandling for me
M@u
-- modified at 11:59 Friday 15th December, 2006
|
|
|
|
|
Could you help me out by explaining where you put this code and how you used it?
Thanks!
|
|
|
|
|
hi
ok here's an example, how you can use it. create a new windowApplication - Project, add a new class, and replace the code with the stuff in my post.
then add a reference to the twainlibrary of this article.
new change to the form and put a Button and a PictureBox on it.
change to the code view and add a member - Variable:
<br />
private TwainMan Scanner;<br />
now change the Constructor. add after InitializeComponent(); the following line:
<br />
Scanner = new TwainMan();<br />
Scanner.ImageScanned += new ImageScannedEventHandler(Scanner_ImageScanned);<br />
now implement the Method Scanner_ImageScanned like this:
<br />
private void Scanner_ImageScanned(object Sender, ImageScannedEventArgs e)<br />
{<br />
pictureBox1.Image = e.Image;<br />
}<br />
now add the ClickEvent - Handler to the Button on the form by doubleclicking it.
the click - Handler of the button should look like this:
<br />
private void button1_Click(object sender, EventArgs e)<br />
{<br />
Scanner.Select();<br />
if (Scanner.Ready)<br />
{<br />
Scanner.Scan();<br />
}<br />
}<br />
that should be it.
greets
m@u
|
|
|
|
|
Error Cannot implicitly convert type 'void' to 'bool'
|
|
|
|
|
Dear m@u,
Is there any way todo this topic without NativeWindow interface? Only by events?
Thanks.
bg
|
|
|
|
|