123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364 |
- // Copyright (c) 2012-2020 fo-dicom contributors.
- // Licensed under the Microsoft Public License (MS-PL).
- using System;
- using System.Collections.Generic;
- using System.Drawing.Printing;
- using System.IO;
- using System.Linq;
- using System.Threading;
- namespace Dicom.Printing
- {
- public class StatusUpdateEventArgs : EventArgs
- {
- public ushort EventTypeId { get; private set; }
- public string ExecutionStatusInfo { get; private set; }
- public string FilmSessionLabel { get; private set; }
- public string PrinterName { get; private set; }
- public StatusUpdateEventArgs(
- ushort eventTypeId,
- string executionStatusInfo,
- string filmSessionLabel,
- string printerName)
- {
- EventTypeId = eventTypeId;
- ExecutionStatusInfo = executionStatusInfo;
- FilmSessionLabel = filmSessionLabel;
- PrinterName = printerName;
- }
- }
- public enum PrintJobStatus : ushort
- {
- Pending = 1,
- Printing = 2,
- Done = 3,
- Failure = 4
- }
- public class PrintJob : DicomDataset
- {
- #region Properties and Attributes
- public bool SendNEventReport { get; set; }
- public Guid PrintJobGuid { get; private set; }
- public IList<string> FilmBoxFolderList { get; private set; }
- public Printer Printer { get; private set; }
- public PrintJobStatus Status { get; private set; }
- public string PrintJobFolder { get; private set; }
- public string FullPrintJobFolder { get; private set; }
- public Exception Error { get; private set; }
- public string FilmSessionLabel { get; private set; }
- private int _currentPage;
- private FilmBox _currentFilmBox;
- /// <summary>
- /// Print job SOP class UID
- /// </summary>
- public readonly DicomUID SOPClassUID = DicomUID.PrintJobSOPClass;
- /// <summary>
- /// Print job SOP instance UID
- /// </summary>
- public DicomUID SOPInstanceUID { get; private set; }
- /// <summary>
- /// Execution status of print job.
- /// </summary>
- /// <remarks>
- /// Enumerated Values:
- /// <list type="bullet">
- /// <item><description>PENDING</description></item>
- /// <item><description>PRINTING</description></item>
- /// <item><description>DONE</description></item>
- /// <item><description>FAILURE</description></item>
- /// </list>
- /// </remarks>
- public string ExecutionStatus
- {
- get => GetSingleValueOrDefault(DicomTag.ExecutionStatus, string.Empty);
- set => AddOrUpdate(DicomTag.ExecutionStatus, value.ToUpperInvariant());
- }
- /// <summary>
- /// Additional information about Execution Status (2100,0020).
- /// </summary>
- public string ExecutionStatusInfo
- {
- get => GetSingleValueOrDefault(DicomTag.ExecutionStatusInfo, string.Empty);
- set => AddOrUpdate(DicomTag.ExecutionStatusInfo, value.ToUpperInvariant());
- }
- /// <summary>
- /// Specifies the priority of the print job.
- /// </summary>
- /// <remarks>
- /// Enumerated values:
- /// <list type="bullet">
- /// <item><description>HIGH</description></item>
- /// <item><description>MED</description></item>
- /// <item><description>LOW</description></item>
- /// </list>
- /// </remarks>
- public string PrintPriority
- {
- get => GetSingleValueOrDefault(DicomTag.PrintPriority, "MED");
- set => AddOrUpdate(DicomTag.PrintPriority, value);
- }
- /// <summary>
- /// Date/Time of print job creation.
- /// </summary>
- public DateTime CreationDateTime
- {
- get => this.GetDateTime(DicomTag.CreationDate, DicomTag.CreationTime);
- set
- {
- AddOrUpdate(DicomTag.CreationDate, value);
- AddOrUpdate(DicomTag.CreationTime, value);
- }
- }
- /// <summary>
- /// User defined name identifying the printer.
- /// </summary>
- public string PrinterName
- {
- get => GetSingleValueOrDefault(DicomTag.PrinterName, string.Empty);
- set => AddOrUpdate(DicomTag.PrinterName, value);
- }
- /// <summary>
- /// DICOM Application Entity Title that issued the print operation.
- /// </summary>
- public string Originator
- {
- get => GetSingleValueOrDefault(DicomTag.Originator, string.Empty);
- set => AddOrUpdate(DicomTag.Originator, value);
- }
- public Log.Logger Log { get; private set; }
- public event EventHandler<StatusUpdateEventArgs> StatusUpdate;
- #endregion
- #region Constructors
- /// <summary>
- /// Construct new print job using specified SOP instance UID. If passed SOP instance UID is missing, new UID will
- /// be generated
- /// </summary>
- /// <param name="sopInstance">New print job SOP instance uID</param>
- public PrintJob(DicomUID sopInstance, Printer printer, string originator, Log.Logger log)
- : base()
- {
- Log = log;
- if (sopInstance == null || sopInstance.UID == string.Empty)
- {
- SOPInstanceUID = DicomUID.Generate();
- }
- else
- {
- SOPInstanceUID = sopInstance;
- }
- Add(DicomTag.SOPClassUID, SOPClassUID);
- Add(DicomTag.SOPInstanceUID, SOPInstanceUID);
- Printer = printer ?? throw new ArgumentNullException("printer");
- Status = PrintJobStatus.Pending;
- PrinterName = Printer.PrinterAet;
- Originator = originator;
- if (CreationDateTime == DateTime.MinValue)
- {
- CreationDateTime = DateTime.Now;
- }
- PrintJobFolder = SOPInstanceUID.UID;
- var receivingFolder = Path.Combine(Environment.CurrentDirectory, "PrintJobs");
- FullPrintJobFolder = Path.Combine(receivingFolder, PrintJobFolder);
- FilmBoxFolderList = new List<string>();
- }
- #endregion
- #region Printing Methods
- public void Print(IList<FilmBox> filmBoxList)
- {
- try
- {
- Status = PrintJobStatus.Pending;
- OnStatusUpdate("QUEUED");
- var printJobDir = new DirectoryInfo(FullPrintJobFolder);
- if (!printJobDir.Exists)
- {
- printJobDir.Create();
- }
- DicomFile file;
- int filmsCount = FilmBoxFolderList.Count;
- for (int i = 0; i < filmBoxList.Count; i++)
- {
- var filmBox = filmBoxList[i];
- var filmBoxDir = printJobDir.CreateSubdirectory(string.Format("F{0:000000}", i + 1 + filmsCount));
- file = new DicomFile(filmBox.FilmSession);
- file.Save(Path.Combine(filmBoxDir.FullName, "FilmSession.dcm"));
- FilmBoxFolderList.Add(filmBoxDir.Name);
- filmBox.Save(filmBoxDir.FullName);
- }
- FilmSessionLabel = filmBoxList.First().FilmSession.FilmSessionLabel;
- var thread = new Thread(new ThreadStart(DoPrint))
- {
- Name = $"PrintJob {SOPInstanceUID.UID}",
- IsBackground = true
- };
- thread.Start();
- }
- catch (Exception ex)
- {
- Error = ex;
- Status = PrintJobStatus.Failure;
- OnStatusUpdate("UNKNOWN"); // The exception may be analyzed and a more proper code as defined in "Table C.13.9.1-1. Defined Terms for Printer and Execution Status Info" may be used
- DeletePrintFolder();
- }
- }
- private void DoPrint()
- {
- PrintDocument printDocument = null;
- try
- {
- Status = PrintJobStatus.Printing;
- OnStatusUpdate("QUEUED");
- var printerSettings = new PrinterSettings
- {
- PrinterName = "Microsoft XPS Document Writer",
- PrintToFile = true,
- PrintFileName = Path.Combine(FullPrintJobFolder, SOPInstanceUID.UID + ".xps")
- };
- printDocument = new PrintDocument
- {
- PrinterSettings = printerSettings,
- DocumentName = Thread.CurrentThread.Name,
- PrintController = new StandardPrintController()
- };
- printDocument.QueryPageSettings += OnQueryPageSettings;
- printDocument.PrintPage += OnPrintPage;
- printDocument.Print();
- Status = PrintJobStatus.Done;
- OnStatusUpdate("NORMAL");
- }
- catch (Exception)
- {
- Status = PrintJobStatus.Failure;
- OnStatusUpdate("UNKNOWN"); // The exception may be analyzed and a more proper code as defined in "Table C.13.9.1-1. Defined Terms for Printer and Execution Status Info" may be used
- }
- finally
- {
- if (printDocument != null)
- {
- //dispose the print document and unregister events handlers to avoid memory leaks
- printDocument.QueryPageSettings -= OnQueryPageSettings;
- printDocument.PrintPage -= OnPrintPage;
- printDocument.Dispose();
- }
- }
- }
- private void OnPrintPage(object sender, PrintPageEventArgs e)
- {
- _currentFilmBox.Print(e.Graphics, e.MarginBounds, 100);
- _currentFilmBox = null;
- _currentPage++;
- e.HasMorePages = _currentPage < FilmBoxFolderList.Count;
- }
- private void OnQueryPageSettings(object sender, QueryPageSettingsEventArgs e)
- {
- OnStatusUpdate($"NORMAL");
- var filmBoxFolder = Path.Combine(FullPrintJobFolder, FilmBoxFolderList[_currentPage]);
- var filmSession = FilmSession.Load(Path.Combine(filmBoxFolder, "FilmSession.dcm"));
- _currentFilmBox = FilmBox.Load(filmSession, filmBoxFolder);
- e.PageSettings.Margins.Left = 25;
- e.PageSettings.Margins.Right = 25;
- e.PageSettings.Margins.Top = 25;
- e.PageSettings.Margins.Bottom = 25;
- e.PageSettings.Landscape = _currentFilmBox.FilmOrientation == "LANDSCAPE";
- }
- private void DeletePrintFolder()
- {
- var folderInfo = new DirectoryInfo(FullPrintJobFolder);
- if (folderInfo.Exists)
- {
- folderInfo.Delete(true);
- }
- }
- #endregion
- #region Notification Methods
- protected virtual void OnStatusUpdate(string info)
- {
- ExecutionStatus = Status.ToString();
- ExecutionStatusInfo = info;
- if (Status != PrintJobStatus.Failure)
- {
- Log.Info("Print Job {0} Status {1}: {2}", SOPInstanceUID.UID.Split('.').Last(), Status, info);
- }
- else
- {
- Log.Error("Print Job {0} Status {1}: {2}", SOPInstanceUID.UID.Split('.').Last(), Status, info);
- }
- StatusUpdate?.Invoke(this, new StatusUpdateEventArgs((ushort)Status, info, FilmSessionLabel, PrinterName));
- }
- #endregion
- }
- }
|