Home › Forums › TWAIN Classic › Nikon Coolscan IV ED TWAIN Memory Transfer
- This topic has 2 replies, 2 voices, and was last updated 10 years, 7 months ago by spike.
- AuthorPosts
Hallo, I have problems with the above Scanner (all other Scanners work fine). In Native Mode the application crashes with an Access violation on
rc = DSixfer(appid, srcds, TwDG.Image, TwDAT.ImageNativeXfer, TwMSG.Get, hbitmap)
and with MemoryTransfer
pImageMemX.BytesWritten
is 0. I assume that perhaps a further initialisation is necessary.
Here is the code:
Public Function TransferPictures() As ArrayList
Dim pics As New ArrayList
If (srcds.Id = IntPtr.Zero) Then
Return pics
End If
Dim rc As TwRC
Dim hbitmap As IntPtr = IntPtr.Zero
Dim pxfr As New TwPendingXfers()
Do
Try
pxfr.Count = 0
hbitmap = IntPtr.Zero
Dim iinf As New TwImageInfo()
Dim iLayout As New TwImageLayout
rc = DSiinf(appid, srcds, TwDG.Image, TwDAT.ImageInfo, TwMSG.Get, iinf)
Dim rc2 As TwRC = DSilayout(appid, srcds, TwDG.Image, TwDAT.ImageLayout, TwMSG.Get, iLayout)
If iinf.PixelType <> TWPT.RGB Then MsgBox("Wrong Pixeltype: " & System.Enum.GetName(GetType(TWPT), CType(iinf.PixelType, TWPT)))
If (rc <> TwRC.Success) Then
CloseSrc()
Return pics
End If
Dim setupMemXfer As New TW_SetupMemXfer()
rc = DsmEntry(appid, srcds, TwMSG.Get, setupMemXfer)
'rc = TwRC.Failure
If rc = TwRC.Success Then
Dim lHasNextBuffer As Boolean = True
Dim pImageMemX As New TwImageMemXFer(setupMemXfer)
pImageMemX.Compression = CUShort(iinf.Compression)
Dim lBuffer, LHBuffer As IntPtr
Dim TotalBytes As UInt32
Dim lMemoryStream As New IO.MemoryStream
Dim fh As New BITMAPFILEHEADER
fh.bfSize = Marshal.SizeOf(fh)
fh.bfType = &H4D42
fh.bfReserved1 = 0
fh.bfReserved2 = 0
fh.bfOffBits = Marshal.SizeOf(fh) + Marshal.SizeOf(GetType(BITMAPINFOHEADER))
Dim bmi As New BITMAPINFOHEADER
bmi.biSize = Marshal.SizeOf(bmi)
bmi.biPlanes = 1
bmi.biBitCount = iinf.BitsPerPixel
bmi.biCompression = iinf.Compression
bmi.biSizeImage = CInt(((((iinf.ImageWidth * iinf.BitsPerPixel + 31) / 32) * 4) * Math.Abs(iinf.ImageLength)))
bmi.biXPelsPerMeter = 0
bmi.biYPelsPerMeter = 0
bmi.biClrUsed = 0
bmi.biClrImportant = 0
bmi.biWidth = iinf.ImageWidth
bmi.biHeight = iinf.ImageLength
lMemoryStream.Seek(0, SeekOrigin.Begin)
Dim pFH, pBMI As IntPtr
Dim FHLength, BMILength As Integer
FHLength = Marshal.SizeOf(fh)
BMILength = Marshal.SizeOf(bmi)
pFH = Marshal.AllocHGlobal(FHLength)
pBMI = Marshal.AllocHGlobal(BMILength)
Marshal.StructureToPtr(fh, pFH, True)
Marshal.StructureToPtr(bmi, pBMI, True)
Dim Arrfh(FHLength - 1) As Byte
Dim ArrBMI(BMILength - 1) As Byte
Marshal.Copy(pFH, Arrfh, 0, FHLength)
Marshal.Copy(pBMI, ArrBMI, 0, BMILength)
lMemoryStream.Write(Arrfh, 0, FHLength)
lMemoryStream.Write(ArrBMI, 0, BMILength)
Marshal.FreeHGlobal(pFH)
Marshal.FreeHGlobal(pBMI)
LHBuffer = GlobalAlloc(&H42, CInt(setupMemXfer.preferred))
lBuffer = GlobalLock(LHBuffer)
pImageMemX.Memory.TheMem = lBuffer
While lHasNextBuffer
Select Case DSmemxfer(appid, srcds, TwDG.Image, TwDAT.ImageMemXfer, TwMSG.Get, pImageMemX)
Case TwRC.Success
If pImageMemX.BytesWritten = 0 Then lHasNextBuffer = False : Exit Select
Dim lByteArray As Byte() = New Byte(CInt(pImageMemX.BytesWritten - 1)) {}
Marshal.Copy(lBuffer, lByteArray, 0, lByteArray.Length)
Debug.Print(CStr(pImageMemX.Memory.Length))
TotalBytes = TotalBytes + pImageMemX.BytesWritten
lMemoryStream.Write(lByteArray, 0, lByteArray.Length)
Dim lMessage As String = String.Format("pimagememx.BytesWritten = {0}", pImageMemX.BytesWritten)
Debug.Print(lMessage)
' Free the current buffer
GlobalUnlock(lBuffer)
GlobalFree(LHBuffer)
LHBuffer = IntPtr.Zero
lBuffer = IntPtr.Zero
LHBuffer = GlobalAlloc(&H42, CInt(setupMemXfer.preferred))
lBuffer = GlobalLock(LHBuffer)
pImageMemX = New TwImageMemXFer(setupMemXfer)
pImageMemX.Memory.TheMem = lBuffer
Exit Select
Case TwRC.XferDone
Dim lByteArray1 As Byte() = New Byte(CInt(pImageMemX.BytesWritten - 1)) {}
Dim lMessage As String = String.Format("pimagememx.BytesWritten = {0}", pImageMemX.BytesWritten)
Debug.Print(lMessage)
Marshal.Copy(lBuffer, lByteArray1, 0, lByteArray1.Length)
TotalBytes = TotalBytes + pImageMemX.BytesWritten
lMemoryStream.Write(lByteArray1, 0, lByteArray1.Length)
Try
Dim img As Image = Image.FromStream(lMemoryStream)
img.RotateFlip(RotateFlipType.RotateNoneFlipY)
lMemoryStream.Close()
GlobalUnlock(lBuffer)
GlobalFree(LHBuffer)
Dim b As Bitmap = DirectCast(img, Bitmap)
Dim width As Integer = img.Width
Dim height As Integer = img.Height
Dim data As BitmapData = b.LockBits(New Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb)
Dim offset As Integer = data.Stride - data.Width * 3
Dim offs As Integer
Dim ptr As IntPtr = data.Scan0
Dim y As Integer = 0
While y < height
Dim x As Integer = 0
While x < width
Dim swap As Byte = Marshal.ReadByte(ptr, offs)
Marshal.WriteByte(ptr, offs, Marshal.ReadByte(ptr, offs + 2))
Marshal.WriteByte(ptr, offs + 2, swap)
x += 1
offs += 3
End While
y += 1
offs += offset
End While
b.UnlockBits(data)
pics.Add(img)
Catch ex As Exception
MsgBox(ex.Message)
End Try
rc = DSpxfer(appid, srcds, TwDG.Control, TwDAT.PendingXfers, TwMSG.EndXfer, pxfr)
If (rc <> TwRC.Success) Then
CloseSrc()
Return pics
End If
lHasNextBuffer = False
Exit Select
Case TwRC.Cancel
Exit Select
Case TwRC.Failure
Exit Select
End Select
End While
Else
Try
rc = DSixfer(appid, srcds, TwDG.Image, TwDAT.ImageNativeXfer, TwMSG.Get, hbitmap)
Catch
End Try
'hbitmap = CType(ptrBitmap, IntPtr)
If (rc <> TwRC.XferDone) Then
CloseSrc()
Return pics
End If
rc = DSpxfer(appid, srcds, TwDG.Control, TwDAT.PendingXfers, TwMSG.EndXfer, pxfr)
If (rc <> TwRC.Success) Then
CloseSrc()
Return pics
End If
pics.Add(hbitmap)
End If
Catch ex As Exception
MsgBox(ex.Message)
CloseSrc()
Return pics
End Try
Loop While pxfr.Count <> 0
rc = DSpxfer(appid, srcds, TwDG.Control, TwDAT.PendingXfers, TwMSG.Reset, pxfr)
Return pics
End FunctionAnd in C#
public ArrayList TransferPictures()
{
ArrayList pics = new ArrayList();
if ((srcds.Id == IntPtr.Zero)) {
return pics;
}
TwRC rc = default(TwRC);
IntPtr hbitmap = IntPtr.Zero;
TwPendingXfers pxfr = new TwPendingXfers();
do {
try {
pxfr.Count = 0;
hbitmap = IntPtr.Zero;
TwImageInfo iinf = new TwImageInfo();
TwImageLayout iLayout = new TwImageLayout();
rc = DSiinf(appid, srcds, TwDG.Image, TwDAT.ImageInfo, TwMSG.Get, iinf);
TwRC rc2 = DSilayout(appid, srcds, TwDG.Image, TwDAT.ImageLayout, TwMSG.Get, iLayout);
if (iinf.PixelType != TWPT.RGB)
Interaction.MsgBox("Wrong Pixeltype: " + System.Enum.GetName(typeof(TWPT), (TWPT)iinf.PixelType));
if ((rc != TwRC.Success)) {
CloseSrc();
return pics;
}
TW_SetupMemXfer setupMemXfer = new TW_SetupMemXfer();
rc = DsmEntry(appid, srcds, TwMSG.Get, setupMemXfer);
//rc = TwRC.Failure
if (rc == TwRC.Success) {
bool lHasNextBuffer = true;
TwImageMemXFer pImageMemX = new TwImageMemXFer(setupMemXfer);
pImageMemX.Compression = Convert.ToUInt16(iinf.Compression);
IntPtr lBuffer = default(IntPtr);
IntPtr LHBuffer = default(IntPtr);
UInt32 TotalBytes = default(UInt32);
System.IO.MemoryStream lMemoryStream = new System.IO.MemoryStream();
BITMAPFILEHEADER fh = new BITMAPFILEHEADER();
fh.bfSize = Marshal.SizeOf(fh);
fh.bfType = 0x4d42;
fh.bfReserved1 = 0;
fh.bfReserved2 = 0;
fh.bfOffBits = Marshal.SizeOf(fh) + Marshal.SizeOf(typeof(BITMAPINFOHEADER));
BITMAPINFOHEADER bmi = new BITMAPINFOHEADER();
bmi.biSize = Marshal.SizeOf(bmi);
bmi.biPlanes = 1;
bmi.biBitCount = iinf.BitsPerPixel;
bmi.biCompression = iinf.Compression;
bmi.biSizeImage = Convert.ToInt32(((((iinf.ImageWidth * iinf.BitsPerPixel + 31) / 32) * 4) * Math.Abs(iinf.ImageLength)));
bmi.biXPelsPerMeter = 0;
bmi.biYPelsPerMeter = 0;
bmi.biClrUsed = 0;
bmi.biClrImportant = 0;
bmi.biWidth = iinf.ImageWidth;
bmi.biHeight = iinf.ImageLength;
lMemoryStream.Seek(0, SeekOrigin.Begin);
IntPtr pFH = default(IntPtr);
IntPtr pBMI = default(IntPtr);
int FHLength = 0;
int BMILength = 0;
FHLength = Marshal.SizeOf(fh);
BMILength = Marshal.SizeOf(bmi);
pFH = Marshal.AllocHGlobal(FHLength);
pBMI = Marshal.AllocHGlobal(BMILength);
Marshal.StructureToPtr(fh, pFH, true);
Marshal.StructureToPtr(bmi, pBMI, true);
byte[] Arrfh = new byte[FHLength];
byte[] ArrBMI = new byte[BMILength];
Marshal.Copy(pFH, Arrfh, 0, FHLength);
Marshal.Copy(pBMI, ArrBMI, 0, BMILength);
lMemoryStream.Write(Arrfh, 0, FHLength);
lMemoryStream.Write(ArrBMI, 0, BMILength);
Marshal.FreeHGlobal(pFH);
Marshal.FreeHGlobal(pBMI);
LHBuffer = GlobalAlloc(0x42, Convert.ToInt32(setupMemXfer.preferred));
lBuffer = GlobalLock(LHBuffer);
pImageMemX.Memory.TheMem = lBuffer;
while (lHasNextBuffer) {
switch (DSmemxfer(appid, srcds, TwDG.Image, TwDAT.ImageMemXfer, TwMSG.Get, pImageMemX)) {
case TwRC.Success:
if (pImageMemX.BytesWritten == 0){lHasNextBuffer = false;break; // TODO: might not be correct. Was : Exit Select
}
byte[] lByteArray = new byte[Convert.ToInt32(pImageMemX.BytesWritten - 1) + 1];
Marshal.Copy(lBuffer, lByteArray, 0, lByteArray.Length);
Debug.Print(Convert.ToString(pImageMemX.Memory.Length));
TotalBytes = TotalBytes + pImageMemX.BytesWritten;
lMemoryStream.Write(lByteArray, 0, lByteArray.Length);
string lMessage = string.Format("pimagememx.BytesWritten = {0}", pImageMemX.BytesWritten);
Debug.Print(lMessage);
// Free the current buffer
GlobalUnlock(lBuffer);
GlobalFree(LHBuffer);
LHBuffer = IntPtr.Zero;
lBuffer = IntPtr.Zero;
LHBuffer = GlobalAlloc(0x42, Convert.ToInt32(setupMemXfer.preferred));
lBuffer = GlobalLock(LHBuffer);
pImageMemX = new TwImageMemXFer(setupMemXfer);
pImageMemX.Memory.TheMem = lBuffer;
break; // TODO: might not be correct. Was : Exit Select
break;
case TwRC.XferDone:
byte[] lByteArray1 = new byte[Convert.ToInt32(pImageMemX.BytesWritten - 1) + 1];
string lMessage = string.Format("pimagememx.BytesWritten = {0}", pImageMemX.BytesWritten);
Debug.Print(lMessage);
Marshal.Copy(lBuffer, lByteArray1, 0, lByteArray1.Length);
TotalBytes = TotalBytes + pImageMemX.BytesWritten;
lMemoryStream.Write(lByteArray1, 0, lByteArray1.Length);
try {
Image img = Image.FromStream(lMemoryStream);
img.RotateFlip(RotateFlipType.RotateNoneFlipY);
lMemoryStream.Close();
GlobalUnlock(lBuffer);
GlobalFree(LHBuffer);
Bitmap b = (Bitmap)img;
int width = img.Width;
int height = img.Height;
BitmapData data = b.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
int offset = data.Stride - data.Width * 3;
int offs = 0;
IntPtr ptr = data.Scan0;
int y = 0;
while (y < height) {
int x = 0;
while (x < width) {
byte swap = Marshal.ReadByte(ptr, offs);
Marshal.WriteByte(ptr, offs, Marshal.ReadByte(ptr, offs + 2));
Marshal.WriteByte(ptr, offs + 2, swap);
x += 1;
offs += 3;
}
y += 1;
offs += offset;
}
b.UnlockBits(data);
pics.Add(img);
} catch (Exception ex) {
Interaction.MsgBox(ex.Message);
}
rc = DSpxfer(appid, srcds, TwDG.Control, TwDAT.PendingXfers, TwMSG.EndXfer, pxfr);
if ((rc != TwRC.Success)) {
CloseSrc();
return pics;
}
lHasNextBuffer = false;
break; // TODO: might not be correct. Was : Exit Select
break;
case TwRC.Cancel:
break; // TODO: might not be correct. Was : Exit Select
break;
case TwRC.Failure:
break; // TODO: might not be correct. Was : Exit Select
break;
}
}
} else {
try {
rc = DSixfer(appid, srcds, TwDG.Image, TwDAT.ImageNativeXfer, TwMSG.Get, hbitmap);
} catch {
}
//hbitmap = CType(ptrBitmap, IntPtr)
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);
}
} catch (Exception ex) {
Interaction.MsgBox(ex.Message);
CloseSrc();
return pics;
}
} while (pxfr.Count != 0);
rc = DSpxfer(appid, srcds, TwDG.Control, TwDAT.PendingXfers, TwMSG.Reset, pxfr);
return pics;
}Regards Hans
I got the code working by setting the following capability:
If Me.blnMemXFer Then SetCap(TwCap.IXferMech, twsx.MEMORY) Else SetCap(TwCap.IXferMech, twsx.NATIVE)
The only problem is now that if PixelType is Grey the image gets distortet.
Regards
Hans
What’s the distortion look like?
Are you taking account of the fact that in a bitmap (DIB) the size of each row is a multiple of 4 bytes?
I see you using that to calculate the size of the DIB, but I don’t see you padding each row up to a multiple of 4 bytes when you copy data from the buffer during memory transfer.
Also, Windows has no concept of grayscale DIB – grayscale images are managed as 256-color DIBs. So there has to be a 256-entry color table after the header, and I don’t see that either.
I just skimmed the code, I’m sorry if I missed something!- AuthorPosts