#74 expose memory transfer data as-is.

This commit is contained in:
Eugene Wang
2017-02-02 19:48:01 -05:00
parent 7a8b0d0772
commit 0852092e11
8 changed files with 91 additions and 65 deletions

1
.gitignore vendored
View File

@@ -156,3 +156,4 @@ $RECYCLE.BIN/
.DS_Store .DS_Store
/packages /packages
*.nupkg *.nupkg
/.vs

View File

@@ -71,8 +71,7 @@
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="ModernWpf.Core, Version=2.0.0.0, Culture=neutral, PublicKeyToken=c99d0cfbea7491ef, processorArchitecture=MSIL"> <Reference Include="ModernWpf.Core, Version=2.0.0.0, Culture=neutral, PublicKeyToken=c99d0cfbea7491ef, processorArchitecture=MSIL">
<HintPath>..\..\packages\ModernWpf.Core.2.0.0-alpha94\lib\net40-Client\ModernWpf.Core.dll</HintPath> <HintPath>..\..\packages\ModernWpf.Core.2.0.0-alpha96\lib\net40-Client\ModernWpf.Core.dll</HintPath>
<Private>True</Private>
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Data" /> <Reference Include="System.Data" />

View File

@@ -274,7 +274,8 @@ namespace Sample.WPF
void _session_TransferReady(object sender, TransferReadyEventArgs e) void _session_TransferReady(object sender, TransferReadyEventArgs e)
{ {
if (_session.CurrentSource.Capabilities.ICapXferMech.GetCurrent() == XferMech.File) var mech = _session.CurrentSource.Capabilities.ICapXferMech.GetCurrent();
if (mech == XferMech.File)
{ {
var formats = _session.CurrentSource.Capabilities.ICapImageFileFormat.GetValues(); var formats = _session.CurrentSource.Capabilities.ICapImageFileFormat.GetValues();
var wantFormat = formats.Contains(FileFormat.Tiff) ? FileFormat.Tiff : FileFormat.Bmp; var wantFormat = formats.Contains(FileFormat.Tiff) ? FileFormat.Tiff : FileFormat.Bmp;
@@ -286,6 +287,11 @@ namespace Sample.WPF
}; };
var rc = _session.CurrentSource.DGControl.SetupFileXfer.Set(fileSetup); var rc = _session.CurrentSource.DGControl.SetupFileXfer.Set(fileSetup);
} }
else if (mech == XferMech.Memory)
{
// ?
}
} }
string GetUniqueName(string dir, string name, string ext) string GetUniqueName(string dir, string name, string ext)
@@ -315,19 +321,28 @@ namespace Sample.WPF
ImageSource GenerateThumbnail(DataTransferredEventArgs e) ImageSource GenerateThumbnail(DataTransferredEventArgs e)
{ {
BitmapSource img = null; BitmapSource img = null;
if (e.NativeData != IntPtr.Zero)
switch (e.TransferType)
{ {
using (var stream = e.GetNativeImageStream()) case XferMech.Native:
{ using (var stream = e.GetNativeImageStream())
if (stream != null)
{ {
img = stream.ConvertToWpfBitmap(300, 0); if (stream != null)
{
img = stream.ConvertToWpfBitmap(300, 0);
}
} }
} break;
} case XferMech.File:
else if (!string.IsNullOrEmpty(e.FileDataPath)) img = new BitmapImage(new Uri(e.FileDataPath));
{ if (img.CanFreeze)
img = new BitmapImage(new Uri(e.FileDataPath)); {
img.Freeze();
}
break;
case XferMech.Memory:
// TODO: build current image from multiple data-xferred event
break;
} }
//if (img != null) //if (img != null)

View File

@@ -4,6 +4,6 @@
<package id="Microsoft.WindowsAPICodePack-Core" version="1.1.0.2" targetFramework="net4-client" /> <package id="Microsoft.WindowsAPICodePack-Core" version="1.1.0.2" targetFramework="net4-client" />
<package id="Microsoft.WindowsAPICodePack-Shell" version="1.1.0.0" targetFramework="net4-client" /> <package id="Microsoft.WindowsAPICodePack-Shell" version="1.1.0.0" targetFramework="net4-client" />
<package id="ModernWpf" version="2.0.0-alpha94" targetFramework="net40-client" /> <package id="ModernWpf" version="2.0.0-alpha94" targetFramework="net40-client" />
<package id="ModernWpf.Core" version="2.0.0-alpha94" targetFramework="net40-client" /> <package id="ModernWpf.Core" version="2.0.0-alpha96" targetFramework="net40-client" />
<package id="MvvmLightLibs" version="5.3.0.0" targetFramework="net40-client" /> <package id="MvvmLightLibs" version="5.3.0.0" targetFramework="net40-client" />
</packages> </packages>

View File

@@ -1921,9 +1921,9 @@ namespace NTwain.Data
} }
/// <summary> /// <summary>
/// Describes the form of the acquired data being passed from the Source to the application. /// Describes the form of the acquired data being passed from the Source to the application in memory transfer mode.
/// </summary> /// </summary>
partial class TWImageMemXfer public partial class TWImageMemXfer
{ {
/// <summary> /// <summary>
/// The compression method used to process the data being transferred. /// The compression method used to process the data being transferred.
@@ -1965,7 +1965,7 @@ namespace NTwain.Data
/// buffer, the actual size of the buffer, in bytes, and where the buffer is /// buffer, the actual size of the buffer, in bytes, and where the buffer is
/// located in memory. /// located in memory.
/// </summary> /// </summary>
public TWMemory Memory { get { return _memory; } internal set { _memory = value; } } internal TWMemory Memory { get { return _memory; } set { _memory = value; } }
} }
/// <summary> /// <summary>

View File

@@ -25,17 +25,19 @@ namespace NTwain
/// <param name="nativeData">The native data.</param> /// <param name="nativeData">The native data.</param>
public DataTransferredEventArgs(DataSource source, IntPtr nativeData) public DataTransferredEventArgs(DataSource source, IntPtr nativeData)
{ {
TransferType = XferMech.Native;
DataSource = source; DataSource = source;
NativeData = nativeData; NativeData = nativeData;
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="DataTransferredEventArgs"/> class. /// Initializes a new instance of the <see cref="DataTransferredEventArgs" /> class.
/// </summary> /// </summary>
/// <param name="source">The source.</param> /// <param name="source">The source.</param>
/// <param name="fileDataPath">The file data path.</param> /// <param name="fileDataPath">The file data path.</param>
/// <param name="imageFileFormat">The image file format.</param> /// <param name="imageFileFormat">The image file format.</param>
public DataTransferredEventArgs(DataSource source, string fileDataPath, FileFormat imageFileFormat) public DataTransferredEventArgs(DataSource source, string fileDataPath, FileFormat imageFileFormat)
{ {
TransferType = XferMech.File;
DataSource = source; DataSource = source;
FileDataPath = fileDataPath; FileDataPath = fileDataPath;
ImageFileFormat = imageFileFormat; ImageFileFormat = imageFileFormat;
@@ -44,15 +46,26 @@ namespace NTwain
/// Initializes a new instance of the <see cref="DataTransferredEventArgs" /> class. /// Initializes a new instance of the <see cref="DataTransferredEventArgs" /> class.
/// </summary> /// </summary>
/// <param name="source">The source.</param> /// <param name="source">The source.</param>
/// <param name="memoryInfo">The memory information.</param>
/// <param name="memoryData">The memory data.</param> /// <param name="memoryData">The memory data.</param>
public DataTransferredEventArgs(DataSource source, byte[] memoryData) public DataTransferredEventArgs(DataSource source, TWImageMemXfer memoryInfo, byte[] memoryData)
{ {
TransferType = XferMech.Memory;
DataSource = source; DataSource = source;
MemoryInfo = memoryInfo;
MemoryData = memoryData; MemoryData = memoryData;
} }
/// <summary> /// <summary>
/// Gets pointer to the complete data if the transfer was native. /// Gets the type of the transfer mode.
/// </summary>
/// <value>
/// The type of the transfer.
/// </value>
public XferMech TransferType { get; private set; }
/// <summary>
/// Gets the raw pointer to the complete data if <see cref="TransferType"/> is <see cref="XferMech.Native"/>.
/// The data will be freed once the event handler ends /// The data will be freed once the event handler ends
/// so consumers must complete whatever processing before then. /// so consumers must complete whatever processing before then.
/// For image type this data is DIB (Windows) or TIFF (Linux). /// For image type this data is DIB (Windows) or TIFF (Linux).
@@ -63,6 +76,7 @@ namespace NTwain
/// <summary> /// <summary>
/// Gets the file path to the complete data if the transfer was file or memory-file. /// Gets the file path to the complete data if the transfer was file or memory-file.
/// This is only available if <see cref="TransferType"/> is <see cref="XferMech.File"/>.
/// </summary> /// </summary>
/// <value> /// <value>
/// The file path. /// The file path.
@@ -71,12 +85,22 @@ namespace NTwain
/// <summary> /// <summary>
/// Gets the file format if applicable. /// Gets the file format if applicable.
/// This is only available if <see cref="TransferType"/> is <see cref="XferMech.Memory"/>.
/// </summary> /// </summary>
/// <value> /// <value>
/// The file format. /// The file format.
/// </value> /// </value>
public FileFormat ImageFileFormat { get; private set; } public FileFormat ImageFileFormat { get; private set; }
/// <summary>
/// Gets the info object if the transfer was memory.
/// This is only available if <see cref="TransferType"/> is <see cref="XferMech.Memory"/>.
/// </summary>
/// <value>
/// The memory information.
/// </value>
public TWImageMemXfer MemoryInfo { get; private set; }
/// <summary> /// <summary>
/// Gets the raw memory data if the transfer was memory. /// Gets the raw memory data if the transfer was memory.
/// Consumer application will need to do the parsing based on the values /// Consumer application will need to do the parsing based on the values
@@ -166,7 +190,7 @@ namespace NTwain
{ {
retVal = ImageTools.GetTiffStream(NativeData); retVal = ImageTools.GetTiffStream(NativeData);
} }
} }
return retVal; ; return retVal; ;
} }

View File

@@ -99,7 +99,7 @@ namespace NTwain.Internals
} }
} }
} }
if (rc != ReturnCode.Success && session.StopOnTransferError) if (rc != ReturnCode.Success && session.StopOnTransferError)
{ {
// end xfer without setting rc to exit (good/bad?) // end xfer without setting rc to exit (good/bad?)
@@ -234,7 +234,7 @@ namespace NTwain.Internals
{ {
lockedPtr = PlatformInfo.Current.MemoryManager.Lock(dataPtr); lockedPtr = PlatformInfo.Current.MemoryManager.Lock(dataPtr);
} }
DoImageXferredEventRoutine(session, lockedPtr, null, null, (FileFormat)0); DoImageXferredEventRoutine(session, lockedPtr, null, null, null, (FileFormat)0);
} }
else else
{ {
@@ -276,7 +276,7 @@ namespace NTwain.Internals
var xrc = session.DGImage.ImageFileXfer.Get(); var xrc = session.DGImage.ImageFileXfer.Get();
if (xrc == ReturnCode.XferDone) if (xrc == ReturnCode.XferDone)
{ {
DoImageXferredEventRoutine(session, IntPtr.Zero, null, filePath, setupInfo.Format); DoImageXferredEventRoutine(session, IntPtr.Zero, null, null, filePath, setupInfo.Format);
} }
else else
{ {
@@ -304,50 +304,37 @@ namespace NTwain.Internals
TheMem = PlatformInfo.Current.MemoryManager.Allocate(memInfo.Preferred) TheMem = PlatformInfo.Current.MemoryManager.Allocate(memInfo.Preferred)
}; };
// do the unthinkable and keep all xferred batches in memory,
// possibly defeating the purpose of mem xfer do
// unless compression is used.
// todo: use array instead of memory stream?
using (MemoryStream xferredData = new MemoryStream())
{ {
do xrc = session.DGImage.ImageMemXfer.Get(xferInfo);
if (xrc == ReturnCode.Success ||
xrc == ReturnCode.XferDone)
{ {
xrc = session.DGImage.ImageMemXfer.Get(xferInfo); if (session.State != 7) { session.ChangeState(7, true); }
if (xrc == ReturnCode.Success || // optimize and allocate buffer only once instead of inside the loop?
xrc == ReturnCode.XferDone) byte[] buffer = new byte[(int)xferInfo.BytesWritten];
IntPtr lockPtr = IntPtr.Zero;
try
{ {
session.ChangeState(7, true); lockPtr = PlatformInfo.Current.MemoryManager.Lock(xferInfo.Memory.TheMem);
// optimize and allocate buffer only once instead of inside the loop? Marshal.Copy(lockPtr, buffer, 0, buffer.Length);
byte[] buffer = new byte[(int)xferInfo.BytesWritten]; }
finally
IntPtr lockPtr = IntPtr.Zero; {
try if (lockPtr != IntPtr.Zero)
{ {
lockPtr = PlatformInfo.Current.MemoryManager.Lock(xferInfo.Memory.TheMem); PlatformInfo.Current.MemoryManager.Unlock(xferInfo.Memory.TheMem);
Marshal.Copy(lockPtr, buffer, 0, buffer.Length);
xferredData.Write(buffer, 0, buffer.Length);
}
finally
{
if (lockPtr != IntPtr.Zero)
{
PlatformInfo.Current.MemoryManager.Unlock(xferInfo.Memory.TheMem);
//PlatformInfo.Current.MemoryManager.Unlock(lockPtr);
}
} }
} }
} while (xrc == ReturnCode.Success); DoImageXferredEventRoutine(session, IntPtr.Zero, xferInfo, buffer, null, (FileFormat)0);
}
} while (xrc == ReturnCode.Success);
if (xrc == ReturnCode.XferDone) HandleReturnCode(session, xrc);
{
DoImageXferredEventRoutine(session, IntPtr.Zero, xferredData.ToArray(), null, (FileFormat)0);
}
else
{
HandleReturnCode(session, xrc);
}
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -449,13 +436,13 @@ namespace NTwain.Internals
if (File.Exists(finalFile)) if (File.Exists(finalFile))
{ {
DoImageXferredEventRoutine(session, IntPtr.Zero, null, finalFile, fileInfo.Format); DoImageXferredEventRoutine(session, IntPtr.Zero, null, null, finalFile, fileInfo.Format);
} }
} }
return xrc; return xrc;
} }
static void DoImageXferredEventRoutine(ITwainSessionInternal session, IntPtr dataPtr, byte[] dataArray, string filePath, FileFormat format) static void DoImageXferredEventRoutine(ITwainSessionInternal session, IntPtr dataPtr, TWImageMemXfer memInfo, byte[] memData, string filePath, FileFormat format)
{ {
DataTransferredEventArgs args = null; DataTransferredEventArgs args = null;
@@ -463,9 +450,9 @@ namespace NTwain.Internals
{ {
args = new DataTransferredEventArgs(session.CurrentSource, dataPtr); args = new DataTransferredEventArgs(session.CurrentSource, dataPtr);
} }
else if (dataArray != null) else if (memData != null)
{ {
args = new DataTransferredEventArgs(session.CurrentSource, dataArray); args = new DataTransferredEventArgs(session.CurrentSource, memInfo, memData);
} }
else else
{ {

View File

@@ -23,7 +23,7 @@ namespace NTwain
/// <summary> /// <summary>
/// The build release version number. /// The build release version number.
/// </summary> /// </summary>
public const string Build = "3.3.9.5"; // change this for each nuget release public const string Build = "3.4.0"; // change this for each nuget release
} }