Duplex ntwain kann nicht scannenC#

Ein Treffpunkt für C#-Programmierer
Anonymous
 Duplex ntwain kann nicht scannen

Post by Anonymous »

Ich habe diesen Code für C# auf .NET 4.8 mit NTWain 3.7.5 in einer Konsolen -App, aber wenn ich versuche, im Duplex -Modus zu scannen, erhalte ich in einigen Fällen nur eine Seite pro PDF, die generiert wurde, wenn der Scanner -Scan mehr als 1 Seite aktiviert wurde, und offensichtlich, wenn der Duplex mindestens 2 Seiten zurückgeben muss. Wo ist das Problem mit diesem Code? Kann mir bitte jemand helfen? < /P>

Code: Select all

using NTwain;
using NTwain.Data;
using PdfSharp.Drawing;
using PdfSharp.Pdf;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading;
using System.Windows.Forms;

namespace ScanService.Utilities
{
public static class TwainScanner
{
private static ManualResetEvent _waitScan = new ManualResetEvent(false);

public static byte[] ScanAndReturnPdfBytes(string documentName, int resolution, bool useADF, bool duplex, string colorMode, string sheetSize)
{
Console.WriteLine("\n=== INICIO ESCANEO ===");
Console.WriteLine($"📄 Documento: {documentName}, Resolución: {resolution}, ADF: {useADF}, Dúplex: {duplex}, Color: {colorMode}, Tamaño: {sheetSize}");

List scannedBitmaps = new List();
_waitScan.Reset();

Thread staThread = new Thread(() =>
{
TwainSession session = null;
DataSource source = null;

try
{
session = new TwainSession(TWIdentity.CreateFromAssembly(DataGroups.Image, typeof(TwainScanner).Assembly));
session.Open();

if (session.State < 3)
{
Console.WriteLine("❌ No se pudo iniciar TWAIN.");
_waitScan.Set();
Application.ExitThread();
return;
}

var scannerName = ScannerConfig.SelectedScannerName;
source = session.GetSources().FirstOrDefault(s => s.Name.Equals(scannerName, StringComparison.OrdinalIgnoreCase));

if (source == null)
{
Console.WriteLine($"❌ Escáner '{scannerName}' no encontrado.");
_waitScan.Set();
Application.ExitThread();
return;
}

EventHandler onError = (s, e) =>
{
Console.WriteLine("❌ Error de transferencia: " + e.Exception?.Message);
_waitScan.Set();
Application.ExitThread();
};

EventHandler onTransferred = (s, e) =>
{
if (e.NativeData != IntPtr.Zero)
{
try
{
using (var stream = e.GetNativeImageStream())
using (var tmp = new Bitmap(stream))
{
Bitmap cleanBmp = new Bitmap(tmp);
scannedBitmaps.Add(cleanBmp);
}

Console.WriteLine($"✅ Imagen escaneada en memoria (total: {scannedBitmaps.Count})");
}
catch (Exception ex)
{
Console.WriteLine("❌ Error al procesar imagen: "  + ex.Message);
}
}
else
{
Console.WriteLine("⚠️ Imagen vacía recibida.");
}
};

EventHandler onDisabled = (s, e) =>
{
Console.WriteLine("📴 Escaneo finalizado por el escáner.");
_waitScan.Set();
Application.ExitThread();
};

session.TransferError += onError;
session.DataTransferred += onTransferred;
session.SourceDisabled += onDisabled;

source.Open();

SetCap(source.Capabilities.ICapXResolution, new TWFix32 { Whole = (short)resolution });
SetCap(source.Capabilities.ICapYResolution, new TWFix32 { Whole = (short)resolution });

PixelType pixelType;
var color = (colorMode ?? "").Trim().ToLowerInvariant();
if (color == "color")
pixelType = PixelType.RGB;
else if (color == "blackwhite")
pixelType = PixelType.BlackWhite;
else
pixelType = PixelType.Gray;

SetCap(source.Capabilities.ICapPixelType, pixelType);

SetCap(source.Capabilities.CapFeederEnabled, useADF ? BoolType.True : BoolType.False);
SetCap(source.Capabilities.CapAutoFeed, useADF ? BoolType.True : BoolType.False);
SetCap(source.Capabilities.CapDuplexEnabled, duplex ? BoolType.True : BoolType.False);

Console.WriteLine("📥 ADF: " + (useADF ? "Habilitado" : "Deshabilitado"));
Console.WriteLine("📄 Dúplex: " + (duplex ? "Habilitado" : "Deshabilitado"));

var rc = source.Enable(SourceEnableMode.NoUI, false, IntPtr.Zero);
if (rc != ReturnCode.Success)
{
Console.WriteLine("❌ No se pudo iniciar el escaneo.");
_waitScan.Set();
Application.ExitThread();
return;
}

Application.Run();

session.TransferError -= onError;
session.DataTransferred -= onTransferred;
session.SourceDisabled -= onDisabled;
}
catch (Exception ex)
{
Console.WriteLine("❌ Error en el hilo STA: " + ex.Message);
_waitScan.Set();
Application.ExitThread();
}
finally
{
try
{
if (session?.State >= 4)
source?.Close();
}
catch { }

try
{
if (session?.State >= 3)
session?.Close();
}
catch { }

source = null;
session = null;

GC.Collect();
GC.WaitForPendingFinalizers();

Thread.Sleep(250);
}
});

staThread.SetApartmentState(ApartmentState.STA);
staThread.Start();
_waitScan.WaitOne(TimeSpan.FromMinutes(5));

if (scannedBitmaps.Count == 0)
{
Console.WriteLine("❌ No se escanearon páginas.");
return null;
}

try
{
using (MemoryStream output = new MemoryStream())
using (PdfDocument pdf = new PdfDocument())
{
foreach (Bitmap bmp in scannedBitmaps)
{
PdfPage page = pdf.AddPage();
var dims = GetPageDimensions(sheetSize);
page.Width = XUnit.FromInch(dims.Item1);
page.Height = XUnit.FromInch(dims.Item2);

using (XGraphics gfx = XGraphics.FromPdfPage(page))
using (MemoryStream ms = new MemoryStream())
{
bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
ms.Position = 0;
using (XImage ximg = XImage.FromStream(ms))
{
gfx.DrawImage(ximg, 0, 0, page.Width.Point, page.Height.Point);
}
}
}

pdf.Save(output, false);
return output.ToArray();
}
}
catch (Exception ex)
{
Console.WriteLine("❌ Error al generar PDF: " + ex.Message);
return null;
}
finally
{
foreach (var bmp in scannedBitmaps)
{
try { bmp.Dispose(); } catch { }
}
}
}

private static bool SetCap(ICapWrapper cap, T value) where T : struct
{
try
{
if (cap != null && cap.IsSupported)
{
cap.SetValue(value);
return true;
}
}
catch (Exception ex)
{
Console.WriteLine($"❌ Error al setear capacidad: {ex.Message}");
}
return false;
}

private static Tuple GetPageDimensions(string size)
{
if (string.IsNullOrEmpty(size)) return Tuple.Create(8.5, 11.0);
size = size.Trim().ToLower();

if (size == "oficio")
return Tuple.Create(8.5, 13.0);

if (size == "credencial")
return Tuple.Create(3.37, 2.13);

if (size == "1/2 carta horizontal")
return Tuple.Create(8.5, 5.5);

if (size == "1/2 carta vertical")
return Tuple.Create(5.5, 8.5);

if (size == "a4")
return Tuple.Create(8.27, 11.69);

return Tuple.Create(8.5, 11.0);
}
}
}

Quick Reply

Change Text Case: 
   
  • Similar Topics
    Replies
    Views
    Last post