|
Rotation is not supported by all scanner.
You can try first to verify if the capability is supported.
I suggest you to rotate scanned image with GDI+
|
|
|
|
|
I recommend you first to scan the initial image without transform it and after when you have the bitmap in your hand you can use this class:
using System;
using System.Drawing;
namespace RotateImage
{
///
/// Summary description for Utilities.
///
public sealed class Utilities
{
private Utilities()
{
}
///
/// Creates a new Image containing the same image only rotated
///
/// <param name="image" />The <see cref="System.Drawing.Image"> to rotate
/// <param name="angle" />The amount to rotate the image, clockwise, in degrees
/// <returns>A new <see cref="System.Drawing.Bitmap"> that is just large enough
/// to contain the rotated image without cutting any corners off.
/// <exception cref="System.ArgumentNullException">Thrown if <see cref="image"> is null.
public static Bitmap RotateImage(Image image, float angle)
{
if(image == null)
throw new ArgumentNullException("image");
const double pi2 = Math.PI / 2.0;
// Why can't C# allow these to be const, or at least readonly
// *sigh* I'm starting to talk like Christian Graus
double oldWidth = (double) image.Width;
double oldHeight = (double) image.Height;
// Convert degrees to radians
double theta = ((double) angle) * Math.PI / 180.0;
double locked_theta = theta;
// Ensure theta is now [0, 2pi)
while( locked_theta < 0.0 )
locked_theta += 2 * Math.PI;
double newWidth, newHeight;
int nWidth, nHeight; // The newWidth/newHeight expressed as ints
#region Explaination of the calculations
/*
* The trig involved in calculating the new width and height
* is fairly simple; the hard part was remembering that when
* PI/2 <= theta <= PI and 3PI/2 <= theta < 2PI the width and
* height are switched.
*
* When you rotate a rectangle, r, the bounding box surrounding r
* contains for right-triangles of empty space. Each of the
* triangles hypotenuse's are a known length, either the width or
* the height of r. Because we know the length of the hypotenuse
* and we have a known angle of rotation, we can use the trig
* function identities to find the length of the other two sides.
*
* sine = opposite/hypotenuse
* cosine = adjacent/hypotenuse
*
* solving for the unknown we get
*
* opposite = sine * hypotenuse
* adjacent = cosine * hypotenuse
*
* Another interesting point about these triangles is that there
* are only two different triangles. The proof for which is easy
* to see, but its been too long since I've written a proof that
* I can't explain it well enough to want to publish it.
*
* Just trust me when I say the triangles formed by the lengths
* width are always the same (for a given theta) and the same
* goes for the height of r.
*
* Rather than associate the opposite/adjacent sides with the
* width and height of the original bitmap, I'll associate them
* based on their position.
*
* adjacent/oppositeTop will refer to the triangles making up the
* upper right and lower left corners
*
* adjacent/oppositeBottom will refer to the triangles making up
* the upper left and lower right corners
*
* The names are based on the right side corners, because thats
* where I did my work on paper (the right side).
*
* Now if you draw this out, you will see that the width of the
* bounding box is calculated by adding together adjacentTop and
* oppositeBottom while the height is calculate by adding
* together adjacentBottom and oppositeTop.
*/
#endregion
double adjacentTop, oppositeTop;
double adjacentBottom, oppositeBottom;
// We need to calculate the sides of the triangles based
// on how much rotation is being done to the bitmap.
// Refer to the first paragraph in the explaination above for
// reasons why.
if( (locked_theta >= 0.0 && locked_theta < pi2) ||
(locked_theta >= Math.PI && locked_theta < (Math.PI + pi2) ) )
{
adjacentTop = Math.Abs(Math.Cos(locked_theta)) * oldWidth;
oppositeTop = Math.Abs(Math.Sin(locked_theta)) * oldWidth;
adjacentBottom = Math.Abs(Math.Cos(locked_theta)) * oldHeight;
oppositeBottom = Math.Abs(Math.Sin(locked_theta)) * oldHeight;
}
else
{
adjacentTop = Math.Abs(Math.Sin(locked_theta)) * oldHeight;
oppositeTop = Math.Abs(Math.Cos(locked_theta)) * oldHeight;
adjacentBottom = Math.Abs(Math.Sin(locked_theta)) * oldWidth;
oppositeBottom = Math.Abs(Math.Cos(locked_theta)) * oldWidth;
}
newWidth = adjacentTop + oppositeBottom;
newHeight = adjacentBottom + oppositeTop;
nWidth = (int) Math.Ceiling(newWidth);
nHeight = (int) Math.Ceiling(newHeight);
Bitmap rotatedBmp = new Bitmap(nWidth, nHeight);
using(Graphics g = Graphics.FromImage(rotatedBmp))
{
// This array will be used to pass in the three points that
// make up the rotated image
Point [] points;
/*
* The values of opposite/adjacentTop/Bottom are referring to
* fixed locations instead of in relation to the
* rotating image so I need to change which values are used
* based on the how much the image is rotating.
*
* For each point, one of the coordinates will always be 0,
* nWidth, or nHeight. This because the Bitmap we are drawing on
* is the bounding box for the rotated bitmap. If both of the
* corrdinates for any of the given points wasn't in the set above
* then the bitmap we are drawing on WOULDN'T be the bounding box
* as required.
*/
if( locked_theta >= 0.0 && locked_theta < pi2 )
{
points = new Point[] {
new Point( (int) oppositeBottom, 0 ),
new Point( nWidth, (int) oppositeTop ),
new Point( 0, (int) adjacentBottom )
};
}
else if( locked_theta >= pi2 && locked_theta < Math.PI )
{
points = new Point[] {
new Point( nWidth, (int) oppositeTop ),
new Point( (int) adjacentTop, nHeight ),
new Point( (int) oppositeBottom, 0 )
};
}
else if( locked_theta >= Math.PI && locked_theta < (Math.PI + pi2) )
{
points = new Point[] {
new Point( (int) adjacentTop, nHeight ),
new Point( 0, (int) adjacentBottom ),
new Point( nWidth, (int) oppositeTop )
};
}
else
{
points = new Point[] {
new Point( 0, (int) adjacentBottom ),
new Point( (int) oppositeBottom, 0 ),
new Point( (int) adjacentTop, nHeight )
};
}
g.DrawImage(image, points);
}
return rotatedBmp;
}
}
}
|
|
|
|
|
Hello,
How i can understand that no scanner attached to computer?
Thanks for your help.
|
|
|
|
|
I found the code hangs if you try to select a scanner with no scanner attached. I solved this by returning the TwRC value at the end of the Select method. A return of "EndOfList" means there are no scanners attached.
|
|
|
|
|
Can you please paste the code of select method here?
|
|
|
|
|
Hi, all
I try to check scanner device before scanning
But when I get CAP_DEVICEONLINE capability , I always get TRUE result !
Can any body help me?
volodymyr_
|
|
|
|
|
I have a HP 1400 scanner and I used this code and it worked fine. But when I tried to change the DPI it did not work out.
I defied TW_ONEVALUE, TW_RANGE, TW_ENUMARATION structs and tried to set the resolution via "TwDG.Control, TwDAT.Capability, TwMSG.Set" for XRESOLUTION AND YRESOLUTION. But everytime it scans at 96 DPI, however the size of Picture varies, i.e. it gives big picture for high resolution and small picture for low resolution.
Now the problem is, How can I keep the size of the image to its original size and Set The DPI as I need.
Any help in this matter would be highly appreciated.
Syed Adi Umair.
****Be Modest, A lot have been achieved before you came.****
-- modified at 9:36 Saturday 6th May, 2006
|
|
|
|
|
I'm trying to achieve the same goal.
Did you find the solution to set scanning DPI?
Thanks,
Mosquets
|
|
|
|
|
<dllimport("gdiplus.dll", exactspelling:="True," charset:="CharSet.Unicode)"> Friend Shared Function GdipBitmapSetResolution(ByVal image As IntPtr, ByVal xDpi As Single, ByVal yDpi As Single) As Integer
End Function
GdipBitmapSetResolution(img, 300.0, 300.0)
|
|
|
|
|
Here is my code below:
ArrayList pics = tw.TransferPictures();
IntPtr bmpptr = GlobalLock((IntPtr)pics[pics.Count - 1]);//get the last
IntPtr pixptr = GetPixelInfo(bmpptr);
IntPtr img = new IntPtr();
int st = Gdip.GdipCreateBitmapFromGdiDib(bmpptr, pixptr, ref img);
if ((st != 0) || (img == IntPtr.Zero)) return;
Byte[] picBuffer=new Byte[Marshal.SizeOf(img)];
Marshal.Copy(img,picBuffer,0,Marshal.SizeOf(img));
pictureBox.Image = Image.FromStream(new MemoryStream(picBuffer));
An InvalidArgument Exception happens in the last line.
Any help is apprecited.
|
|
|
|
|
hi firststar,
read all the post here i found this code:
Public Function ImgToBitmap(ByVal dibhandp As IntPtr) As Bitmap
bmprect = New Rectangle(0, 0, 0, 0)
dibhand = dibhandp
bmpptr = GlobalLock(dibhand)
pixptr = GetPixelInfo(bmpptr)
Dim TempBMP As Bitmap = New Bitmap(bmprect.Width, bmprect.Height)
Dim TempGrap As Graphics = Graphics.FromImage(TempBMP)
Dim hdc As IntPtr = TempGrap.GetHdc
SetDIBitsToDevice(hdc, 0, 0, bmprect.Width, bmprect.Height, 0, 0, 0, bmprect.Height, pixptr, bmpptr, 0)
TempGrap.ReleaseHdc(hdc)
TempGrap.Dispose()
GlobalFree(dibhand)
dibhand = IntPtr.Zero
Return (TempBMP)
End Function
this function transform the image scan to a bitmap and after you can pass this result to a picture box:
I modify the class picForm, and i create a new class name scanToImage here is the code:
scanToImage.vb
----------------------------------------------------------------------------------
Imports System
Imports System.Text
Imports System.Runtime.InteropServices
Imports System.Drawing
Imports System.Collections
Imports System.ComponentModel
Namespace TwainGui
<structlayout(layoutkind.sequential, pack:="2)"> Friend Class BITMAPINFOHEADER
Public biSize As Integer
Public biWidth As Integer
Public biHeight As Integer
Public biPlanes As Short
Public biBitCount As Short
Public biCompression As Integer
Public biSizeImage As Integer
Public biXPelsPerMeter As Integer
Public biYPelsPerMeter As Integer
Public biClrUsed As Integer
Public biClrImportant As Integer
End Class
Public Class scanToImage
<dllimport("gdi32.dll", exactspelling:="True)"> Friend Shared Function SetDIBitsToDevice(ByVal hdc As IntPtr, ByVal xdst As Integer, ByVal ydst As Integer, ByVal width As Integer, ByVal height As Integer, ByVal xsrc As Integer, ByVal ysrc As Integer, ByVal start As Integer, ByVal lines As Integer, ByVal bitsptr As IntPtr, ByVal bmiptr As IntPtr, ByVal color As Integer) As Integer
End Function
<dllimport("kernel32.dll", exactspelling:="True)"> Friend Shared Function GlobalLock(ByVal handle As IntPtr) As IntPtr
End Function
<dllimport("kernel32.dll", exactspelling:="True)"> Friend Shared Function GlobalFree(ByVal handle As IntPtr) As IntPtr
End Function
<dllimport("kernel32.dll", charset:="CharSet.Auto)"> Public Shared Sub OutputDebugString(ByVal outstr As String)
End Sub
Dim bmi As BITMAPINFOHEADER
Dim bmprect As Rectangle
Dim dibhand As IntPtr
Dim bmpptr As IntPtr
Dim pixptr As IntPtr
Public Sub New(ByVal dibhandp As IntPtr)
bmprect = New Rectangle(0, 0, 0, 0)
dibhand = dibhandp
bmpptr = GlobalLock(dibhand)
pixptr = GetPixelInfo(bmpptr)
End Sub
Protected Function GetPixelInfo(ByVal bmpptr As IntPtr) As IntPtr
bmi = New BITMAPINFOHEADER()
Marshal.PtrToStructure(bmpptr, bmi)
bmprect.X = bmprect.Y = 0
bmprect.Width = bmi.biWidth
bmprect.Height = bmi.biHeight
If (bmi.biSizeImage = 0) Then
bmi.biSizeImage = Int((((bmi.biWidth * bmi.biBitCount) + 31) & Hex(Not (31))) / 2 ^ 3) * bmi.biHeight
End If
Dim p As Integer = bmi.biClrUsed
If ((p = 0) And (bmi.biBitCount <= 8)) Then
p = Int(1 * 2 ^ bmi.biBitCount)
End If
p = (p * 4) + bmi.biSize + CType(bmpptr.ToInt32, Integer)
Return New IntPtr(p)
End Function
Public Function ImgToBitmap(ByVal dibhandp As IntPtr) As Bitmap
bmprect = New Rectangle(0, 0, 0, 0)
dibhand = dibhandp
bmpptr = GlobalLock(dibhand)
pixptr = GetPixelInfo(bmpptr)
Dim TempBMP As Bitmap = New Bitmap(bmprect.Width, bmprect.Height)
Dim TempGrap As Graphics = Graphics.FromImage(TempBMP)
Dim hdc As IntPtr = TempGrap.GetHdc
SetDIBitsToDevice(hdc, 0, 0, bmprect.Width, bmprect.Height, 0, 0, 0, bmprect.Height, pixptr, bmpptr, 0)
TempGrap.ReleaseHdc(hdc)
TempGrap.Dispose()
GlobalFree(dibhand)
dibhand = IntPtr.Zero
Return (TempBMP)
End Function
End Class
End Namespace
-------------------------------------------------------------------------------
and here is the place where i call this function:
-------------------------------------------------------------------------------
...
Public Function PreFilterMessage(ByRef m As Message) As Boolean Implements IMessageFilter.PreFilterMessage
Dim cmd As TwainCommand = tw.PassMessage(m)
If (cmd = TwainCommand.Not) Then
Return False
End If
Select Case cmd
Case TwainCommand.CloseRequest
EndingScan()
tw.CloseSrc()
Case TwainCommand.CloseOk
EndingScan()
tw.CloseSrc()
Case TwainCommand.DeviceEvent
Case TwainCommand.TransferReady
'Obtenemos las Imagenes Scaneadas
Dim pics As ArrayList = tw.TransferPictures()
'Finalizamos el scaneo
EndingScan()
'Cerramos Scanner
tw.CloseSrc()
'Contador pora el numero de imagenes scaneadas
picnumber += 1
Dim i As Integer
'Recorremos el numero de Imagenes para mostrarlas en un PicBox cada una
For i = 0 To pics.Count - 1 Step 1
Dim img As IntPtr = CType(pics(i), IntPtr)
Dim scan As New scanToImage(img)
Dim imagen As Image
anchoPrincipal = panelPrincipal.Width
altoPrincipal = panelPrincipal.Height
imagen = scan.ImgToBitmap(img)
Me.AutoScroll = True
Dim picnum As Integer = i + 1
Dim picActual As PictureBox
picActual = Me.CrearPicture(i)
picActual.SizeMode = PictureBoxSizeMode.StretchImage
picActual.Image = imagen
Next
End Select
Return True
End Function
...
-------------------------------------------------------------------------------
But i have one error, when you scan for the first time all is right, but when you try to scan for second time whitout close the aplication when you do anyone action the application is close, i try to fix this but i can, i hope you can help me.
i hope my code help you and you can help me
PD. sorry about the english but i'm mexican and my english is not good
|
|
|
|
|
Thanks for your code here.
But I am not familar with Visual Basic.
Sorry for not able to help.
|
|
|
|
|
http://www.smalleranimals.com/dc/dcboard.php?az=show_topic&forum=105&topic_id=627&mode=full&page=5[^]
I found a very nice solution on that address. Thanks Tom. This solution works with references. It use less memory then other ones. It's very important when you works with large pictures.
using System.Drawing;
using System.Reflection;
// . . .
[DllImport("GdiPlus.dll", CharSet=CharSet.Unicode,
ExactSpelling=true)]
private static extern int GdipCreateBitmapFromGdiDib(IntPtr pBIH,
IntPtr pPix, out IntPtr pBitmap);
public static Bitmap BitmapFromDIB(IntPtr pDIB)
{
// verify DIB ...
// get pointer to DIB pixels, e.g.,
IntPtr pPix = Gdip.GetPixelInfo(pDIB);
if (pPix == IntPtr.Zero)
return null; // failure ...
// might want a try-catch here instead
MethodInfo mi = typeof(Bitmap).GetMethod("FromGDIplus",
BindingFlags.Static | BindingFlags.NonPublic);
if (mi == null)
return null; // (permission problem)
IntPtr pBmp = IntPtr.Zero;
int status = GdipCreateBitmapFromGdiDib(pDIB, pPix, out pBmp);
if ((status == 0) && (pBmp != IntPtr.Zero))
// success
return (Bitmap)mi.Invoke(null, new object[] {pBmp});
else
return null; // failure
}
|
|
|
|
|
|
Hi,
Here you have another solution in C#:
///
/// Conviert the pointer of scanning image to bitmap
///
/// <returns>
private Bitmap ImgToBitmap()
{
ArrayList pics = tw.TransferPictures();
EndingScan();
tw.CloseSrc();
if (pics.Count == 0) return null;
IntPtr img = (IntPtr)pics[pics.Count - 1];
IntPtr bmpptr = Twain.GlobalLock(img);
IntPtr pixptr = GetPixelInfo(bmpptr);
Twain.BITMAPINFOHEADER bmi = new Twain.BITMAPINFOHEADER();
Marshal.PtrToStructure(bmpptr, bmi);
int PrWidth = bmi.biWidth;
int PrHeight = bmi.biHeight;
Bitmap TempBMP = new Bitmap(PrWidth, PrHeight);
//TempBMP.SetResolution(resolution,resolution);
Graphics TempGrap = Graphics.FromImage(TempBMP);
TempGrap.Clear(Color.White);
IntPtr hdc = TempGrap.GetHdc();
Twain.SetDIBitsToDevice(hdc, 0, 0, PrWidth, PrHeight,
0, 0, 0, PrHeight, pixptr, bmpptr, 0);
TempGrap.ReleaseHdc(hdc);
TempGrap.Dispose();
Twain.GlobalFree(img);
img = IntPtr.Zero;
pics.Clear();
return (TempBMP);
}
Enjoy it
|
|
|
|
|
to the post above - awsome code, you saved my life...thank you
|
|
|
|
|
Bug Description:
I have a scanner installed on my computer,but the power supply is turned off.
So when I click the Acquire menuitem of the TWAIN.NET image scanner, an error message is shown.After I clike the OK button on it, the mainform is disabled.
A possible correction:
public enum TwainCommand
{
......
NotDeviceEvent = 5//add another command
}
public TwainCommand PassMessage( ref Message m )
{
......
if( rc==TwRC.Failure )
return TwainCommand.Not;
if( rc == TwRC.NotDSEvent )
return TwainCommand.NotDeviceEvent;
......
}
public TwainCommand PassMessage( ref Message m )
{
......
if (cmd == TwainCommand.Not)
{
Application.RemoveMessageFilter(this);
msgfilter = false;
this.Enabled = true;
this.Activate();
return false;
}
if (cmd == TwainCommand.NotDeviceEvent)
{
this.Enabled = false;
return false;
}
......
}
|
|
|
|
|
its a vb 2005 project, and the workspace is marked private becasue I don't know how to un-mark it as private yet, but it should auto accept your application to join.
http://www.gotdotnet.com/workspaces/workspace.aspx?id=e93d10b6-d8f0-4bc0-affe-0c6549e857d7
gabe
|
|
|
|
|
and now its public (don't have to join) at a new address
http://www.gotdotnet.com/workspaces/workspace.aspx?id=dd75a486-e2da-4547-b475-20739327b376
|
|
|
|
|
HI Anyone can scan multi tiff image?????
Please help.
THX
|
|
|
|
|
In the "Acquire" method in TwainLib.cs change:
TwCapability cap = new TwCapability( TwCap.XferCount, 1 );
to
TwCapability cap = new TwCapability( TwCap.XferCount, -1 );
The last parameter specifies the number of pages to scan.
Felix.
|
|
|
|
|
|
This doesn't seem to work for me.
The scanner GUI closes automatically after scanning the first page.
|
|
|
|
|
" This doesn't seem to work for me.
The scanner GUI closes automatically after scanning the first page. "
is the same for me!!!
someone knows another way?!
Please... need much!
|
|
|
|
|
When i set
TwCapability cap = new TwCapability( TwCap.XferCount, -1 );
i can't stop the scanner when it's running (after click a stop button with command: tw.Finish())
Who can help me,
Thanks and Best regard
--
Nguyen Kiem Hieu
FPT Information System Company
Defense-Sercurity-Education sector
Address: 2nd floor, 101 Lang Ha St, Dongda Dis, Hanoi, Vietnam
Mobile: (+84)0902 216 369
Website: http://www.fis.com.vn
Email: hieunk2@fpt.com.vn
|
|
|
|
|