У меня есть приложение для архивирования WPF, которое может использовать для сканирования как TWAIN, так и WIA.Все было хорошо, некоторые сканеры работали с Twain отлично, а некоторые старые с WIA.Пока клиент не купил canon dr-f120!
Что ж, теперь WIA работает нормально, но не поддерживает дуплекс, и Twain (!!), все захваченные изображения Twain - серые.![Twain captured images](https://i.stack.imgur.com/4P4Yw.png)
Я пробовал это с другими сканерами, и это было хорошо.Я использовал Saraff TWAIN, поэтому подумал, что может быть проблема с ним, я скачал его образцы, и ни один из них не работал с этим странным сканером!Поэтому я искал другое решение и нашел NTwain , и его образец WPF работал со сканером canon 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;
}
}
}