我有一个WPF存档应用程序,可以同时使用TWAIN和WIA进行扫描。一切都很好,有些扫描仪与twain完美配合,而有些扫描仪与WIA完美配合。直到客户购买了佳能dr-f120!
好吧,现在WIA可以正常工作,但是它不支持双工,并且twain(!!)和Twain捕获的图像都是灰色的。
我在其他扫描仪上尝试过,很好。我当时使用的是Saraff TWAIN,所以我想也许是有问题的,我下载了它的样本,但没有一个能与此怪异的扫描仪一起使用!因此,我寻找了另一个解决方案,结果发现NTwain,其WPF样本可与佳能dr-f120扫描仪一起使用。
因此,现在我使用的是新的TWAIN,它再次都是灰色的!我不明白为什么会这样。这是我使用twain的方法:
我有一个抽象类,可以在TWAIN和WIA之间切换:
public abstract class AbstractScanner
{
protected bool showScannerUI;
protected int fileCounter = 1;
protected List<string> scans = new List<string>();
protected string defaultDevice, tempPath = string.Format("{0}SAMControls.ScannerTmp", Path.GetTempPath());
public event EventHandler ScannerEvent;
public string TempPath
{
set { tempPath = value; }
get { return tempPath; }
}
public string DefaultDevice
{
set { defaultDevice = value; }
get { return defaultDevice; }
}
public void Configurator(string defaultScanner, bool showUI)
{
showScannerUI = showUI;
defaultDevice = defaultScanner;
}
public void RaiseScannerEvent(object sender)
{
if (ScannerEvent != null)
ScannerEvent.Invoke(sender, new ScannerEventArgs { ImagesPath = new List<string>(scans) });
}
public string GenerateTempAddress(string extension)
{
string temp = string.Format("{0}{1}.{2}", tempPath, fileCounter, extension);
while (File.Exists(temp))
{
fileCounter++;
temp = string.Format("{0}{1}.{2}", tempPath, fileCounter, extension);
}
fileCounter++;
return temp;
}
public abstract List<string> GetScannersList();
public abstract void Acquire();
public abstract void Dispose();
}
然后Saraff Twain的实现是:
public class TwainHandler : AbstractScanner
{
Twain32 twain;
ImageSource img;
ScanMode scanMode;
bool initialized = false;
private bool Initializer()
{
twain = new Twain32();
twain.OpenDSM();
if (!string.IsNullOrEmpty(defaultDevice))
for (int i = 0; i < twain.SourcesCount; i++)
if (twain.GetSourceProductName(i) == defaultDevice)
{
twain.SourceIndex = i;
break;
}
twain.OpenDataSource();
twain.ShowUI = showScannerUI;
if (twain.Capabilities.Compression.IsSupported() != 0)
{
twain.Capabilities.Compression.Set(TwCompression.Jpeg);
}
//twain.SetCap(TwCap.IXferMech, TwSX.Memory);
//twain.SetupMemXferEvent += Twain_SetupMemXferEvent;
//twain.MemXferEvent += Twain_MemXferEvent;
//scanMode = ScanMode.Memory;
if (twain.Capabilities.XferMech.IsSupported() != 0)
{
twain.SetCap(TwCap.IXferMech, TwSX.File);
twain.SetupFileXferEvent += Twain_SetupFileXferEvent;
twain.FileXferEvent += Twain_FileXferEvent;
scanMode = ScanMode.File;
}
else
{
twain.SetCap(TwCap.IXferMech, TwSX.Memory);
twain.SetupMemXferEvent += Twain_SetupMemXferEvent;
twain.MemXferEvent += Twain_MemXferEvent;
scanMode = ScanMode.Memory;
}
twain.AcquireCompleted += AcquireCompleted;
return true;
}
public override List<string> GetScannersList()
{
twain = new Twain32();
twain.OpenDSM();
List<string> output = new List<string>();
for (int i = 0; i < twain.SourcesCount; i++)
output.Add(twain.GetSourceProductName(i));
twain.Dispose();
return output;
}
private void Twain_SetupMemXferEvent(object sender, Twain32.SetupMemXferEventArgs e)
{
PixelFormat _format = PixelFormats.Default;
BitmapPalette _pallete = null;
switch (e.ImageInfo.PixelType)
{
case TwPixelType.BW:
_format = PixelFormats.BlackWhite;
break;
case TwPixelType.Gray:
_format = new Dictionary<short, PixelFormat> {
{2,PixelFormats.Gray2},
{4,PixelFormats.Gray4},
{8,PixelFormats.Gray8},
{16,PixelFormats.Gray16}
}[e.ImageInfo.BitsPerPixel];
break;
case TwPixelType.Palette:
_pallete = new BitmapPalette(new Func<IList<System.Windows.Media.Color>>(() =>
{
var _res = new Collection<System.Windows.Media.Color>();
var _colors = twain.Palette.Get().Colors;
for (int i = 0; i < _colors.Length; i++)
{
_res.Add(System.Windows.Media.Color.FromArgb(_colors[i].A, _colors[i].R, _colors[i].G, _colors[i].B));
}
return _res;
})());
_format = new Dictionary<short, PixelFormat> {
{2,PixelFormats.Indexed1},
{4,PixelFormats.Indexed2},
{8,PixelFormats.Indexed4},
{16,PixelFormats.Indexed8}
}[e.ImageInfo.BitsPerPixel];
break;
case TwPixelType.RGB:
_format = new Dictionary<short, PixelFormat> {
{8,PixelFormats.Rgb24},
{24,PixelFormats.Rgb24},
{16,PixelFormats.Rgb48},
{48,PixelFormats.Rgb48}
}[e.ImageInfo.BitsPerPixel];
break;
default:
break;
}
img = new WriteableBitmap(
e.ImageInfo.ImageWidth,
e.ImageInfo.ImageLength,
e.ImageInfo.XResolution,
e.ImageInfo.YResolution,
_format,
_pallete);
scans.Add(GenerateTempAddress("jpg"));
}
private void Twain_MemXferEvent(object sender, Twain32.MemXferEventArgs e)
{
(img as WriteableBitmap).WritePixels(
new Int32Rect(0, 0, (int)e.ImageMemXfer.Columns, (int)e.ImageMemXfer.Rows),
e.ImageMemXfer.ImageData,
(int)e.ImageMemXfer.BytesPerRow,
(int)e.ImageMemXfer.XOffset,
(int)e.ImageMemXfer.YOffset);
using (var filestream = new FileStream(scans[scans.Count - 1], FileMode.Create))
{
JpegBitmapEncoder encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(img as WriteableBitmap));
encoder.Save(filestream);
}
}
private void Twain_SetupFileXferEvent(object sender, Twain32.SetupFileXferEventArgs e)
{
e.FileName = GenerateTempAddress("bmp");
scans.Add(e.FileName);
}
private void Twain_FileXferEvent(object sender, Twain32.FileXferEventArgs e)
{
using (Image image = LoadBitmapUnlocked(scans[scans.Count - 1]))
{
string file = GenerateTempAddress("jpg");
image.Save(file, System.Drawing.Imaging.ImageFormat.Jpeg);
File.Delete(scans[scans.Count - 1]);
scans[scans.Count - 1] = file;
}
}
private void AcquireCompleted(object sender, EventArgs e)
{
if (scanMode == ScanMode.Memory)
{
string tempAddress;
for (int i = 0; i < twain.ImageCount; i++)
{
tempAddress = GenerateTempAddress("jpg");
twain.GetImage(i).Save(tempAddress, System.Drawing.Imaging.ImageFormat.Jpeg);
scans.Add(tempAddress);
}
}
RaiseScannerEvent(sender);
Dispose();
}
public override void Acquire()
{
if (!initialized)
initialized = Initializer();
if (initialized)
twain.Acquire();
else
RaiseScannerEvent(null);
}
private Bitmap LoadBitmapUnlocked(string file_name)
{
using (Bitmap bm = new Bitmap(file_name))
{
return new Bitmap(bm);
}
}
public override void Dispose()
{
scans.Clear();
if (twain != null)
{
twain.CloseDataSource();
twain.CloseDSM();
twain.Dispose();
}
initialized = false;
}
}
和NTWAIN:
public class NTwainHandler : AbstractScanner
{
ImageSource img;
DataSource myDS;
TwainSession _session;
private IntPtr _winHandle;
public IntPtr WindowHandle
{
get { return _winHandle; }
set
{
_winHandle = value;
}
}
public NTwainHandler()
{
var appId = TWIdentity.CreateFromAssembly(DataGroups.Image | DataGroups.Audio, Assembly.GetEntryAssembly());
_session = new TwainSession(appId);
_session.TransferError += _session_TransferError;
_session.TransferReady += _session_TransferReady;
_session.DataTransferred += _session_DataTransferred;
_session.SourceDisabled += _session_SourceDisabled;
// _session.StateChanged += (s, e) => { RaisePropertyChanged(() => State); };
}
public override void Acquire()
{
_session.Open();
myDS = _session.FirstOrDefault();
myDS.Open();
_session.CurrentSource.Capabilities.ICapXferMech.SetValue(XferMech.File); /////////////////// Scanner Mode
var rc = _session.CurrentSource.Enable(showScannerUI ? SourceEnableMode.ShowUI : SourceEnableMode.NoUI, false, WindowHandle);
}
public override void Dispose()
{
}
public override List<string> GetScannersList()
{
_session.Open();
List<string> output = new List<string>();
IEnumerable<DataSource> sources = _session.GetSources();
for (int i = 0, count = sources.Count(); i < count; i++)
output.Add(sources.ElementAt(i).Name);
_session.Close();
return output;
}
void _session_SourceDisabled(object sender, EventArgs e)
{
RaiseScannerEvent(sender);
myDS.Close();
_session.Close();
scans.Clear();
}
void _session_TransferError(object sender, TransferErrorEventArgs e)
{
}
void _session_TransferReady(object sender, TransferReadyEventArgs e)
{
var mech = _session.CurrentSource.Capabilities.ICapXferMech.GetCurrent();
if (mech == XferMech.File)
{
var formats = _session.CurrentSource.Capabilities.ICapImageFileFormat.GetValues();
var wantFormat = formats.Contains(FileFormat.Tiff) ? FileFormat.Tiff : FileFormat.Bmp;
var fileSetup = new TWSetupFileXfer
{
Format = wantFormat,
FileName = GenerateTempAddress("bmp")
// FileName = GetUniqueName(Path.GetTempPath(), "twain-test", "." + wantFormat)
};
var rc = _session.CurrentSource.DGControl.SetupFileXfer.Set(fileSetup);
}
else if (mech == XferMech.Memory)
{
PixelFormat _format = PixelFormats.Default;
BitmapPalette _pallete = null;
switch (e.PendingImageInfo.PixelType)
{
case PixelType.BlackWhite:
_format = PixelFormats.BlackWhite;
break;
case PixelType.Gray:
_format = new Dictionary<short, PixelFormat> {
{2,PixelFormats.Gray2},
{4,PixelFormats.Gray4},
{8,PixelFormats.Gray8},
{16,PixelFormats.Gray16}
}[e.PendingImageInfo.BitsPerPixel];
break;
case PixelType.RGB:
_format = new Dictionary<short, PixelFormat> {
{8,PixelFormats.Rgb24},
{24,PixelFormats.Rgb24},
{16,PixelFormats.Rgb48},
{48,PixelFormats.Rgb48}
}[e.PendingImageInfo.BitsPerPixel];
break;
default:
break;
}
img = new WriteableBitmap(
e.PendingImageInfo.ImageWidth,
e.PendingImageInfo.ImageLength,
e.PendingImageInfo.XResolution,
e.PendingImageInfo.YResolution,
_format,
_pallete);
}
}
void _session_DataTransferred(object sender, DataTransferredEventArgs e)
{
string filePath;
switch (e.TransferType)
{
case XferMech.File:
scans.Add(e.FileDataPath);
break;
case XferMech.Memory:
filePath = GenerateTempAddress("jpg");
(img as WriteableBitmap).WritePixels(
new Int32Rect(0, 0, (int)e.MemoryInfo.Columns, (int)e.MemoryInfo.Rows),
e.MemoryData,
(int)e.MemoryInfo.BytesPerRow,
(int)e.MemoryInfo.XOffset,
(int)e.MemoryInfo.YOffset);
using (var filestream = new FileStream(filePath, FileMode.Create))
{
JpegBitmapEncoder encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(img as WriteableBitmap));
encoder.Save(filestream);
}
scans.Add(filePath);
break;
case XferMech.Native:
filePath = GenerateTempAddress("jpg");
using (Stream nativeStream = e.GetNativeImageStream())
{
JpegBitmapEncoder encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(img as WriteableBitmap));
encoder.Save(nativeStream);
}
scans.Add(filePath);
break;
case XferMech.MemFile:
break;
}
}
}