diff --git a/NTwain.Net35/NTwain.Net35.csproj b/NTwain.Net35/NTwain.Net35.csproj
index 7e75245..fa555cd 100644
--- a/NTwain.Net35/NTwain.Net35.csproj
+++ b/NTwain.Net35/NTwain.Net35.csproj
@@ -124,11 +124,8 @@
Internals\WrappedManualResetEvent.cs
-
- Interop\BITMAPINFO.cs
-
-
- Interop\BITMAPINFOHEADER.cs
+
+ Interop\BITMAP.cs
Interop\MESSAGE.cs
@@ -136,6 +133,9 @@
Interop\NativeMethods.cs
+
+ Interop\TIFF.cs
+
Interop\UnsafeNativeMethods.cs
diff --git a/NTwain/DataTransferredEventArgs.cs b/NTwain/DataTransferredEventArgs.cs
index f3e93dd..21bb750 100644
--- a/NTwain/DataTransferredEventArgs.cs
+++ b/NTwain/DataTransferredEventArgs.cs
@@ -143,16 +143,16 @@ namespace NTwain
/// Gets the bitmap from the if it's an image.
///
///
- public Bitmap GetNativeBitmap()
+ public Image GetNativeImage()
{
- Bitmap image = null;
+ Image image = null;
if (NativeData != IntPtr.Zero)
{
- if (PlatformInfo.Current.IsWindows)
+ if (ImageTools.IsDib(NativeData))
{
image = ImageTools.ReadBitmapImage(NativeData);
}
- else if (PlatformInfo.Current.IsLinux)
+ else if (ImageTools.IsTiff(NativeData))
{
image = ImageTools.ReadTiffImage(NativeData);
}
diff --git a/NTwain/ImageTools.cs b/NTwain/ImageTools.cs
index d45c46b..d6d1f6a 100644
--- a/NTwain/ImageTools.cs
+++ b/NTwain/ImageTools.cs
@@ -4,6 +4,7 @@ using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
+using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security;
@@ -14,77 +15,117 @@ namespace NTwain
{
public static class ImageTools
{
- internal static Bitmap ReadBitmapImage(IntPtr dibBitmap)
+ internal static bool IsDib(IntPtr data)
+ {
+ // a quick check not guaranteed correct,
+ // compare first 2 bytes to size of struct (which is also the first field)
+ var test = Marshal.ReadInt16(data);
+ // should be 40
+ return test == BITMAPINFOHEADER.GetByteSize();
+ }
+ internal static bool IsTiff(IntPtr data)
+ {
+ var test = Marshal.ReadInt16(data);
+ // should be II
+ return test == 0x4949;
+ }
+ internal static Bitmap ReadBitmapImage(IntPtr data)
{
Bitmap finalImg = null;
Bitmap tempImg = null;
- if (IsDib(dibBitmap))
+ try
{
- try
- {
- var header = (BITMAPINFOHEADER)Marshal.PtrToStructure(dibBitmap, typeof(BITMAPINFOHEADER));
+ var header = (BITMAPINFOHEADER)Marshal.PtrToStructure(data, typeof(BITMAPINFOHEADER));
- if (header.Validate())
- {
- PixelFormat format = header.GetDrawingPixelFormat();
- tempImg = new Bitmap(header.biWidth, Math.Abs(header.biHeight), header.GetStride(), format, header.GetScan0(dibBitmap));
- ColorPalette pal = header.GetDrawingPalette(dibBitmap);
- if (pal != null)
- {
- tempImg.Palette = pal;
- }
- float xdpi = header.GetXDpi();
- float ydpi = header.GetYDpi();
- if (xdpi != 0 && ydpi == 0)
- {
- ydpi = xdpi;
- }
- else if (ydpi != 0 && xdpi == 0)
- {
- xdpi = ydpi;
- }
- if (xdpi != 0)
- {
- tempImg.SetResolution(xdpi, ydpi);
- }
- if (header.IsBottomUpImage)
- {
- tempImg.RotateFlip(RotateFlipType.RotateNoneFlipY);
- }
- finalImg = tempImg;
- tempImg = null;
- }
- }
- finally
+ if (header.Validate())
{
- if (tempImg != null)
+ PixelFormat format = header.GetDrawingPixelFormat();
+ tempImg = new Bitmap(header.biWidth, Math.Abs(header.biHeight), header.GetStride(), format, header.GetScan0(data));
+ ColorPalette pal = header.GetDrawingPalette(data);
+ if (pal != null)
{
- tempImg.Dispose();
+ tempImg.Palette = pal;
}
+ float xdpi = header.GetXDpi();
+ float ydpi = header.GetYDpi();
+ if (xdpi != 0 && ydpi == 0)
+ {
+ ydpi = xdpi;
+ }
+ else if (ydpi != 0 && xdpi == 0)
+ {
+ xdpi = ydpi;
+ }
+ if (xdpi != 0)
+ {
+ tempImg.SetResolution(xdpi, ydpi);
+ }
+ if (header.IsBottomUpImage)
+ {
+ tempImg.RotateFlip(RotateFlipType.RotateNoneFlipY);
+ }
+ finalImg = tempImg;
+ tempImg = null;
+ }
+ }
+ finally
+ {
+ if (tempImg != null)
+ {
+ tempImg.Dispose();
}
}
return finalImg;
}
- static bool IsDib(IntPtr dibBitmap)
+ internal static Image ReadTiffImage(IntPtr data)
{
- // a quick check not guaranteed correct,
- // compare first byte to size of struct (which is also the first field)
- var test = Marshal.ReadInt32(dibBitmap);
- // should be 40
- return test == BITMAPINFOHEADER.GetByteSize();
+ // this is modified from twain cs sample
+ // http://sourceforge.net/projects/twainforcsharp/?source=typ_redirect
+
+
+ // Find the size of the image so we can turn it into a memory stream...
+ var headerSize = Marshal.SizeOf(typeof(TIFFHEADER));
+ var tagSize = Marshal.SizeOf(typeof(TIFFTAG));
+ var tiffSize = 0;
+ var header = (TIFFHEADER)Marshal.PtrToStructure(data, typeof(TIFFHEADER));
+ var tagPtr = data.ToInt64() + headerSize;
+ for (int i = 0; i < 999; i++)
+ {
+ tagPtr += (tagSize * i);
+ var tag = (TIFFTAG)Marshal.PtrToStructure((IntPtr)tagPtr, typeof(TIFFTAG));
+
+ switch (tag.u16Tag)
+ {
+ case 273: // StripOffsets...
+ case 279: // StripByteCounts...
+ tiffSize += (int)tag.u32Value;
+ break;
+ }
+ }
+
+ if (tiffSize > 0)
+ {
+ var dataCopy = new byte[tiffSize];
+ Marshal.Copy(data, dataCopy, 0, tiffSize);
+
+ return Image.FromStream(new MemoryStream(dataCopy));
+ }
+ return null;
}
///
- /// Converts a to WPF .
+ /// Converts an to WPF if the image
+ /// is a .
///
/// The image to convert.
///
- public static BitmapSource ConvertToWpfBitmap(this Bitmap image)
+ public static BitmapSource ConvertToWpfBitmap(this Image image)
{
- if (image != null)
+ var bmp = image as Bitmap;
+ if (bmp != null)
{
- using (var hbm = new SafeHBitmapHandle(image.GetHbitmap(), true))
+ using (var hbm = new SafeHBitmapHandle(bmp.GetHbitmap(), true))
{
return System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
hbm.DangerousGetHandle(),
@@ -110,10 +151,5 @@ namespace NTwain
return NativeMethods.DeleteObject(handle);
}
}
-
- internal static Bitmap ReadTiffImage(IntPtr data)
- {
- return null;
- }
}
}
diff --git a/NTwain/Interop/BITMAPINFOHEADER.cs b/NTwain/Interop/BITMAP.cs
similarity index 92%
rename from NTwain/Interop/BITMAPINFOHEADER.cs
rename to NTwain/Interop/BITMAP.cs
index c742438..aeeb6eb 100644
--- a/NTwain/Interop/BITMAPINFOHEADER.cs
+++ b/NTwain/Interop/BITMAP.cs
@@ -7,11 +7,34 @@ using System.Text;
namespace NTwain.Interop
{
+ // this is a good read
+ // http://atlc.sourceforge.net/bmp.html
+
+ ///
+ /// Defines the dimensions and color information for a DIB.
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ struct BITMAPINFO
+ {
+ ///
+ /// Structure that contains information about the dimensions of color format.
+ ///
+ public BITMAPINFOHEADER bmiHeader;
+ ///
+ /// This contains one of the following:
+ /// 1. An array of RGBQUAD. The elements of the array that make up the color table.
+ /// 2. An array of 16-bit unsigned integers that specifies indexes into the currently realized logical palette. This use of bmiColors is allowed for functions that use DIBs.
+ /// The number of entries in the array depends on the values of the biBitCount and biClrUsed members of the BITMAPINFOHEADER structure.
+ ///
+ public IntPtr bmiColors;
+
+ };
+
///
/// Structure that contains information about the dimensions and color format of a DIB.
///
[StructLayout(LayoutKind.Sequential)]
- public struct BITMAPINFOHEADER
+ struct BITMAPINFOHEADER
{
#region fields
///
diff --git a/NTwain/Interop/BITMAPINFO.cs b/NTwain/Interop/BITMAPINFO.cs
deleted file mode 100644
index 2969996..0000000
--- a/NTwain/Interop/BITMAPINFO.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-using System.Runtime.InteropServices;
-using System.Drawing.Imaging;
-using System.Drawing;
-
-namespace NTwain.Interop
-{
- // this is a good read
- // http://atlc.sourceforge.net/bmp.html
-
- ///
- /// Defines the dimensions and color information for a DIB.
- ///
- [StructLayout(LayoutKind.Sequential)]
- public struct BITMAPINFO
- {
- ///
- /// Structure that contains information about the dimensions of color format.
- ///
- public BITMAPINFOHEADER bmiHeader;
- ///
- /// This contains one of the following:
- /// 1. An array of RGBQUAD. The elements of the array that make up the color table.
- /// 2. An array of 16-bit unsigned integers that specifies indexes into the currently realized logical palette. This use of bmiColors is allowed for functions that use DIBs.
- /// The number of entries in the array depends on the values of the biBitCount and biClrUsed members of the BITMAPINFOHEADER structure.
- ///
- public IntPtr bmiColors;
-
- };
-}
diff --git a/NTwain/Interop/TIFF.cs b/NTwain/Interop/TIFF.cs
new file mode 100644
index 0000000..ebfba86
--- /dev/null
+++ b/NTwain/Interop/TIFF.cs
@@ -0,0 +1,35 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace NTwain.Interop
+{
+ // this is from twain cs sample
+ // http://sourceforge.net/projects/twainforcsharp/?source=typ_redirect
+
+ ///
+ /// The TIFF file header.
+ ///
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ struct TIFFHEADER
+ {
+ public ushort u8ByteOrder;
+ public ushort u16Version;
+ public uint u32OffsetFirstIFD;
+ public ushort u16u16IFD;
+ }
+
+ ///
+ /// An individual TIFF Tag.
+ ///
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ struct TIFFTAG
+ {
+ public ushort u16Tag;
+ public ushort u16Type;
+ public uint u32Count;
+ public uint u32Value;
+ }
+}
diff --git a/NTwain/NTwain.csproj b/NTwain/NTwain.csproj
index 413cf2d..cff6439 100644
--- a/NTwain/NTwain.csproj
+++ b/NTwain/NTwain.csproj
@@ -70,13 +70,13 @@
-
-
+
+
diff --git a/README.md b/README.md
index 1e6523a..6b81a24 100644
--- a/README.md
+++ b/README.md
@@ -51,8 +51,8 @@ TwainSession class provides many events, but these 2 are the most important
or all subsequent transfers using the event object.
* DataTransferred - fired after the transfer has occurred. The data available depends on
what you've specified using the TWAIN API before starting the transfer. If using image
-native transfer, the event arg provides a quick GetNativeBitmap() method to convert the
-data to a System.Drawing.Bitmap.
+native transfer, the event arg provides a quick GetNativeImage() method to convert the
+data to a System.Drawing.Image.
NOTE: do not try to close the source/session in the handler of these 2 events or something
unpredictable will happen. Either let the scan run its course or cancel the scan using the flag
@@ -140,7 +140,7 @@ session.Close();
Caveats
--------------------------------------
At the moment the DataTransferredEventArgs only provides conversion routine to
-a Bitmap image when using native transfer.
+an image when using native transfer.
If other transfer methods are used you'll have to deal with them yourself.
If you just call session.Open() without passing a message loop hook argument, an
diff --git a/Tests/Tester.WPF/ViewModels/TwainVM.cs b/Tests/Tester.WPF/ViewModels/TwainVM.cs
index 33ccf7c..5e613f7 100644
--- a/Tests/Tester.WPF/ViewModels/TwainVM.cs
+++ b/Tests/Tester.WPF/ViewModels/TwainVM.cs
@@ -289,7 +289,7 @@ namespace Tester.WPF
BitmapSource img = null;
if (e.NativeData != IntPtr.Zero)
{
- img = e.GetNativeBitmap().ConvertToWpfBitmap();
+ img = e.GetNativeImage().ConvertToWpfBitmap();
}
else if (!string.IsNullOrEmpty(e.FileDataPath))
{
diff --git a/Tests/Tester.Winform/TestForm.cs b/Tests/Tester.Winform/TestForm.cs
index cc73bc6..bbc89e6 100644
--- a/Tests/Tester.Winform/TestForm.cs
+++ b/Tests/Tester.Winform/TestForm.cs
@@ -87,10 +87,10 @@ namespace Tester.Winform
}
// handle image data
- Bitmap img = null;
+ Image img = null;
if (e.NativeData != IntPtr.Zero)
{
- img = e.GetNativeBitmap();
+ img = e.GetNativeImage();
}
else if (!string.IsNullOrEmpty(e.FileDataPath))
{