Home › Forums › TWAIN Classic › How to dynamically determine scanned paper size
- This topic has 11 replies, 3 voices, and was last updated 14 years, 11 months ago by ScannerProgrammer.
- AuthorPosts
I am using C# & Twain to write an application that controls a Canon DR-7080. The problem I am having is that users will often scan documents that are smaller than the standard 8.5×11 sheets of paper. When the image is transferred to a bmp, there is a heavy black border around the image that was scanned. I need to be able to eliminate the border from the image. The software that comes with the scanner has a setting in the paper size selection menu that auto-detects the paper size and crops the image, so I know that the feature is supported by the scanner.
In theTWAIN documentation on page 4-87, it looks like I should be able to get the frame information using TW_ImageLayout. If I run the following code immediately before the image is scanned, the call is successful, but the returned information is wrong because the page hasn’t been scanned yet. If I call it after the scan, the call is unsuccessful because, according to the documentation, the image is already cleared from the TWAIN structures.
TwImageLayout ilyt = new TwImageLayout();
rc = DSilayout(appid, srcds, TwDG.Image, TwDAT.ImageLayout, TwMSG.Get, ilyt);
if (rc != TwRC.Success)
{
CloseSrc();
return pics;
}
float fLeft = ilyt.Frame.Left.ToFloat();
float fRight = ilyt.Frame.Right.ToFloat();
float fTop = ilyt.Frame.Top.ToFloat();I have also experimented with:
TwCapability icapABD = new TwCapability(TwCap.ICAP_AUTOMATICBORDERDETECTION, (short)1);
rc = DScap(appid, srcds, TwDG.Control, TwDAT.Capability, TwMSG.Set, icapABD);
if (rc != TwRC.Success)
{
CloseSrc();
return;
}But TwRC.Success always returns failure. Any ideas?
twImageInfo contains the information you’re lookin for.
my code (vb.net, but it shouldn’t be hard to translate) looks something like this:
Friend Function GetImageInfo() As Boolean
If TwState = 6 Then
Trace.WriteLine("Estimated Image Info")
End If
If TwState = 7 Then
Trace.WriteLine("Actual Image Info")
End If
Dim iinf As New DataStructures.twImageInfo()
If OperationTriplets.Image.ImageInfo.Get(iinf)=Enumerations.ReturnCode.Success Then
Trace.WriteLine("XResolution :" & iinf.XResolution.ToString)
Trace.WriteLine("YResolution :" & iinf.YResolution.ToString)
Trace.WriteLine("ImageWidth :" & iinf.ImageWidth.ToString)
Trace.WriteLine("ImageLength :" & iinf.ImageLength.ToString)
Trace.WriteLine("SamplesPerPixel :" & iinf.SamplesPerPixel.ToString)
Trace.WriteLine("BitsPerSample :" & iinf.BitsPerSample.ToString)
Trace.WriteLine("BitsPerPixel :" & iinf.BitsPerPixel.ToString)
Trace.WriteLine("Planar :" & System.Enum.GetName(GetType(Enumerations.PlanarChunky), iinf.Planar))
Trace.WriteLine("PixelType :" & System.Enum.GetName(GetType(Enumerations.PixelType), iinf.PixelType))
Trace.WriteLine("Compression :" & System.Enum.GetName(GetType(Enumerations.Compression))
Return True
Else
Return False
End If
End Function
I have also tried using Tw_ImageInfo. Here is my call to perform the actual scan:
rc = DSixfer(appid, srcds, TwDG.Image, TwDAT.ImageNativeXfer, TwMSG.Get, ref hbitmap);
if (rc != TwRC.XferDone)
{
CloseSrc();
return pics;
}Until this code executes, the paper is still sitting in the tray waiting to be scanned. If I try retrieving the ImageInfo or FrameInfo first, how could it possibly work since it hasn’t been fed through the machine yet?
When the code executes, the page is fed into the machine and scanned. If I then check FrameInfo, rc returns failure. If I check ImageInfo, all the returned values are the same as they were when I checked them before the scan. I believe that the values being returned are the initial scanner settings for 8.5×11 paper, instead of an image that is sized to the actual paper size.
I hope I am explaining this correctly. Thanks for the reply.
timing. you call it in twState 6 or 7 (pg 238 of the 1.9pspec or my previous post) I call the previous code from the sub that gets the images, and actually when you read most of the sample code available the code you posted is usually unside an if stmt that doesn’t execute unless the code I posted returned True.
Dim PendingXfers As Boolean = True
Do While PendingXfers = True
If GetImageInfo() Then
'Transfer the image natively
hbitmap = IntPtr.Zero
Select Case OperationTriplets.Image.ImageNativeXfer.Get(hbitmap)
Case Enumerations.ReturnCode.XferDone
fileName = NextAvailableFilename(sessionDir.FullName, _
_CurrentImageFileFormat.ToString.ToLower) 'sfd.FileName
Trace.WriteLine(" " & fileName)
Plumbing.DibToBmp.DibHandToBmp(hbitmap).Save(fileName)
_Images.Add(fileName)
PendingXfers = DoEndXfer()
Case Enumerations.ReturnCode.Cancel
PendingXfers = DoEndXfer()
Case Enumerations.ReturnCode.Failure
Dim mStatusShort As Enumerations.ConditionCode
mStatusShort = OperationTriplets.Control.Status.Get()
If mStatusShort <> Enumerations.ConditionCode.Success Then
myTrace.WriteLine(" " & System.Enum.GetName(GetType(Enumerations.ConditionCode), mStatusShort), Instrumentation.TraceLevelEnum.Information)
myTrace.WriteLine(" " & DataStructures.twStatus.ConditionDescription(mStatusShort), Instrumentation.TraceLevelEnum.Information)
End If
DoAbortXfer()
PendingXfers = False
End Select
End If
Loop
Trace.WriteLine("Native loop finished")
the rest of this code is over at http://www.codeplex.com/openTwain on the releases tab in a zip, in a file named cTwain.vb around line 1100ish
.
I have looked through the examples you posted and the OpenTwain project you refer to. I have been using the same logic as you are. I actually got my code from the sample project on http://www.codeproject.com/dotnet/twaindotnet.asp.
This is what I have been running. I apologize for not posting all of it to begin with.
do
{
pxfr.Count = 0;
hbitmap = IntPtr.Zero;
// Per the examples, here is where I am supposed to capture ImageInfo and ImageLayout ...
// But when this code runs the paper is still laying in the tray unscanned.
iinf = new TwImageInfo();
rc = DSiinf(appid, srcds, TwDG.Image, TwDAT.ImageInfo, TwMSG.Get, iinf);
if (rc != TwRC.Success)
{
CloseSrc();
return pics;
}
ilyt = new TwImageLayout();
rc = DSilayout(appid, srcds, TwDG.Image, TwDAT.ImageLayout, TwMSG.Get, ilyt);
if (rc != TwRC.Success)
{
CloseSrc();
return pics;
}
// Store the returned values into my struct - But the values are always the same
// regardless if the paper is 8.5x11 or 5x6
imf = new ImgInfo();
imf.sizeX = iinf.ImageWidth;
imf.sizeY = iinf.ImageLength;
imf.posLeft = ilyt.Frame.Left.ToFloat();
imf.posRight = ilyt.Frame.Right.ToFloat();
imf.posTop = ilyt.Frame.Top.ToFloat();
PictureInfo.Add(imf);
// Now the paper is fed throught the machine and scanned
rc = DSixfer(appid, srcds, TwDG.Image, TwDAT.ImageNativeXfer, TwMSG.Get, ref hbitmap);
if (rc != TwRC.XferDone)
{
CloseSrc();
return pics;
}
// Right here is where I would expect to be able to get my information because the documents have now been scanned.
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);Is there a setting that would cause the scanner to pull in the paper when I call rc = DSiinf(appid, srcds, TwDG.Image, TwDAT.ImageInfo, TwMSG.Get, iinf); and rc = DSiinf(appid, srcds, TwDG.Image, TwDAT.ImageInfo, TwMSG.Get, iinf); ?
yeah , I have yet to see any unique .net code – everybody starts with NetMaster’s code from codeproject. In the background, outside of your current questions there are a couple 2 or 3 problems that everyone using his code usually has to overcome. his twCapability contrutors hard code an address size that should be based on the type of the capability you’re contructing. His code didn’t track the twState, this is invaluable – declare a member variable for track in the twState. Also, check/track the ConditionCode when twRc != success.
Back to your questions,
ImageLayout has never been usful for me. I’m not saying that it is worthless, just that I have yet to find a use for it.the critical part of your code is your ImageNativeXfer Get call.
rc = DSixfer(appid, srcds, TwDG.Image, TwDAT.ImageNativeXfer, TwMSG.Get, ref hbitmap);if you call ImageInfo get before that call you *should* be in twState 6 and the info is estimated, if you call ImageInfo.Get just afterward (and rc== success) you should be in twState7 and the call shoulsd produce the actual values.
Your other question:
Is there a setting that would cause the scanner to pull in the paper when I call rc = DSiinf(appid, srcds, TwDG.Image, TwDAT.ImageInfo, TwMSG.Get, iinf); and rc = DSiinf(appid, srcds, TwDG.Image, TwDAT.ImageInfo, TwMSG.Get, iinf); ?
no. ImageInfo.Get is not documented as causing the paper to feed and there is not setting that turns that on or off – if it is the case with the device you’re using it is just something that vendor decieded to do.
.
I finally found a work around, but not the solution I wanted. I discovered through testing that if I used the Twack32 application to configure the settings, they would be retained and applied when my application runs.
By setting paper size to Auto-Detect and the Detect Width property to Image Size, the scanner delivers a nicely cropped image.
I presume that those settings are configured through undocumented proprietary caps settings.
Thanks to Gabe for trying to help.
twack_32? the toolkit sample twack_32 that you have the source code to?
Not unless you specifically sent a triplet with twack_32, more likely you’re seeing the default behaviour of the device. Many devices retain the capability settings from the last successful acquisition.
But you may be right about their being custom caps on your Canon.Best of luck,
is there an update on this? I have the same issue with it being a white border below the image that is not cropped.
There were settings in my scanner drivers that would cause the machine to scan just the actual image area and fill an 8 x 11 image, eliminating the unwanted border.
I was unable to find any documentation that told me how to access those particular settings programmatically. I ended up just using the Twack application to set those properties. The drivers remember the settings via an ini file so once I set the properties, they will not be changed.
So I am sorry to say I never did come up with a way to use TWAIN to crop the images.
There has got to be a way to set the border detection dynamically without the use of twack32
- AuthorPosts