/// <summary> /// Send the PDF document referenced by "dt" to the PACS system defined in the database lkpInterfaceDefinitions for this document /// effective 1/22/16 the values required to be present in lkpInterfaceDefinitions are as follows: /// interfaceType = "PACS" /// ipAddress, port self explanatory /// stringParam1: "their" AET /// stringParam2: "our" AET /// stringParam3: qualified path to DCMTK binaries, e.g., C:\HUGHES_DCMTK_DICOM\bin /// intParam1: send file type, see enum. 1=pdf, 2=jpg, 3=bmp /// stringParam4: Modality to send to PACS. Defaults to "OT" /// stringParam5: Additional parameters. see documentation for DCMTK "storescu". e.g., when sending a jpg, you might have to specify jpg type, e.g., "-xy" /// </summary> /// <param name="dt">Document Template, as per the HTML document generation</param> /// <param name="patient">V3 Patient object</param> /// <param name="filename">Name of the PDF file to be converted to a .DCM (DICOM) file and transmitted to PACS</param> /// <param name="apptId">Appointment ID</param> /// <returns></returns> public static bool send2PACS(DocumentTemplate dt, RiskApps3.Model.PatientRecord.Patient patient, string filenameIn, int apptId) { List<TripleArg> args = new List<TripleArg>(); // for want of a tuple which doesn't exist till .NET 4.0 List<KeyValuePair<string, string>> dicomOutputArgs = new List<KeyValuePair<string, string>>(); List<InterfaceInstance> interfaces = new List<InterfaceInstance>(); string accessionNumber = ""; string patientname = ""; string dob = ""; string gender = ""; string apptDate = ""; string apptTime = ""; ParameterCollection pacsArgs = new ParameterCollection(); pacsArgs.Add("documentTemplateID", dt.documentTemplateID); string filename; Image img = null; SqlDataReader reader = BCDB2.Instance.ExecuteReaderSPWithParams("sp_getInterfaceDefinitionFromTemplateID", pacsArgs); while (reader.Read()) { InterfaceInstance instance = new InterfaceInstance(); if (reader.IsDBNull(0) == false) { instance.InterfaceId = reader.GetInt32(0); } if (reader.IsDBNull(1) == false) { instance.InterfaceType = reader.GetString(1); } if (reader.IsDBNull(2) == false) { instance.IpAddress = reader.GetString(2); } if (reader.IsDBNull(3) == false) { instance.Port = reader.GetString(3); } if (reader.IsDBNull(4) == false) { instance.AeTitleRemote = reader.GetString(4); } if (reader.IsDBNull(5) == false) { instance.AeTitleLocal = reader.GetString(5); } if (reader.IsDBNull(6) == false) { instance.DCMTKpath = reader.GetString(6); } if (reader.IsDBNull(7) == false) { instance.PacsSubType = reader.GetInt32(7); // for now, 1 == PDF, 2 == JPG, 3 == BMP (see enum pacsSubTypes, above) } // there is no intParam2 for PACS as yet...skipping ahead to the new-as-of-jan-2016 string param 4 if (reader.IsDBNull(9) == false) { instance.Modality = reader.GetString(9); } if (reader.IsDBNull(10) == false) { instance.AdditionalParams = reader.GetString(10); } if (instance.InterfaceId > 0) { interfaces.Add(instance); // multiple PACS interfaces per document are now supported. } } // just do this once... if (apptId > 0) { // This is an FMH specific hack, they are sending the Accession Number in the HL7 ADT_A08 message in PID|26... // and it is being stored in the appointment table in the unused field "referral". // No more obvious way of accomplishing this has jumped out at me yet, but this will have to be made more generic as new // customers are brought on-line. string sqlStr = "SELECT referral,patientname,dob,gender,apptDate,apptTime FROM tblAppointments WHERE apptID=" + apptId.ToString() + ";"; reader = BCDB2.Instance.ExecuteReader(sqlStr); while (reader.Read()) { if (reader.IsDBNull(0) == false) { accessionNumber = reader.GetString(0); } if (reader.IsDBNull(1) == false) // taking this from appointment table, alternatively, could use Patient object { patientname = reader.GetString(1); } if (reader.IsDBNull(2) == false) { dob = reader.GetString(2); } if (reader.IsDBNull(3) == false) { gender = reader.GetString(3); } if (reader.IsDBNull(4) == false) { apptDate = reader.GetString(4); } if (reader.IsDBNull(5) == false) { apptTime = reader.GetString(5); } } reader.Close(); } foreach (InterfaceInstance iface in interfaces) // send document to each eligible interface, converting it as need be { if ((iface.InterfaceId > 0) && (iface.InterfaceType == "PACS")) // no interface? not a PACS interface? bye bye! { // Ok! We're sending this thing to PACS... go ahead and convert the PDF file to a DCM file... // This will call into the DCMTK library to do their pdf2dcm, dcmodify (to set metadata), and storescu. Add appropriate parameters to the DCM. filename = filenameIn; // reinit // filter out oddball cases of calling this method with conflicting interface parameters versus the type of file passed in. // however, we WILL reconvert PDFs to an image upon demand, see below. if (((filename.ToUpper().Contains(".JPG")) || (filename.ToUpper().Contains(".BMP"))) && (iface.PacsSubType == (int)pacsSubTypes.PDF)) { Logger.Instance.WriteToLog("Send2PACS: Attempted to send an image file to a PDF interface, interfaceID #" + iface.InterfaceId + ". Request Aborted" + (apptId > 0 ? " for appt id " + apptId.ToString() + "." : ".")); continue; } if (iface.PacsSubType == (int)pacsSubTypes.JPG) // jpg { // If we were sent a PDF file, yet it's pacsSubType is different, convert the document to an image // this could happen depending on what type of file is generated from the survey, and the settings made in lkpInterfaceDefinitions // as of now, we're not converting between jpgs and bmps... if you send a bmp and interface type is jpg, bail... and vice versa if (filename.ToUpper().Contains(".BMP")) { Logger.Instance.WriteToLog("Send2PACS: Attempted to send a BMP file to a JPG interface. Request Aborted" + (apptId > 0 ? " for appt id " + apptId.ToString() + "." : ".")); continue; } if (filename.ToUpper().Contains(".PDF")) // re-convert this html to an image instead { HtmlToImageConverter htmlToJpgConverter = new HtmlToImageConverter(); htmlToJpgConverter.LicenseKey = "sjwvPS4uPSskPSgzLT0uLDMsLzMkJCQk"; filename = filename.ToUpper().Replace(".PDF", "") + ".jpg"; htmlToJpgConverter.ConvertHtmlToFile(dt.htmlText, "", System.Drawing.Imaging.ImageFormat.Jpeg, filename); } } if ((iface.PacsSubType == (int)pacsSubTypes.BMP) || (iface.PacsSubType == (int)pacsSubTypes.inverseBMP)) // bitmap { // If we were sent a PDF file, yet it's pacsSubType is different, convert the document to an image // this could happen depending on what type of file is generated from the survey, and the settings made in lkpInterfaceDefinitions // as of now, we're not converting between jpgs and bmps... if you send a bmp and interface type is jpg, bail... and vice versa if (filename.ToUpper().Contains(".JPG")) { Logger.Instance.WriteToLog("Send2PACS: Attempted to send a JPG file to a BMP interface. Request Aborted" + (apptId > 0 ? " for appt id " + apptId.ToString() + "." : ".")); continue; } if (filename.ToUpper().Contains(".PDF")) // re-convert this html to an image instead { HtmlToImageConverter htmlToJpgConverter = new HtmlToImageConverter(); htmlToJpgConverter.LicenseKey = "sjwvPS4uPSskPSgzLT0uLDMsLzMkJCQk"; filename = filename.ToUpper().Replace(".PDF", "") + ".bmp"; if (iface.PacsSubType == (int)pacsSubTypes.inverseBMP) { img = htmlToJpgConverter.ConvertHtmlToImageObject(dt.htmlText, ""); } else { htmlToJpgConverter.ConvertHtmlToFile(dt.htmlText, "", System.Drawing.Imaging.ImageFormat.Bmp, filename); } } // jdg 1/26/2016 invert bmp if (iface.PacsSubType == (int)pacsSubTypes.inverseBMP) { InvertBitmap(filename, img); } } args.Clear(); string dcmFilename = filename + ".dcm"; TripleArg arg1 = new TripleArg(); //arg1.ArgSwitch = filename; arg1.ArgSwitch = "\"" + filename + "\""; args.Add(arg1); TripleArg arg2 = new TripleArg(); //arg2.ArgSwitch = dcmFilename; arg2.ArgSwitch = "\"" + dcmFilename + "\""; args.Add(arg2); if ((patient != null) && (iface.PacsSubType == (int)pacsSubTypes.PDF)) // for some reason, img2dcm (jpg) doesn't have a patient identifier arg. will have to insert this into the metadata later. { TripleArg arg3 = new TripleArg(); arg3.ArgSwitch = "+pi"; arg3.Name = patient.unitnum; args.Add(arg3); } if ((iface.PacsSubType == (int)pacsSubTypes.BMP) || (iface.PacsSubType == (int)pacsSubTypes.inverseBMP)) // defaults to jpg { TripleArg arg4 = new TripleArg(); arg4.ArgSwitch = "-i"; arg4.Name = "BMP"; args.Add(arg4); } if ((iface.PacsSubType == (int)pacsSubTypes.JPG) || (iface.PacsSubType == (int)pacsSubTypes.BMP) || (iface.PacsSubType == (int)pacsSubTypes.inverseBMP)) // jpg, bmp { // do the conversion jpg --> dcm; this is a local command, no ip/port needed for this one. wrapDCMTKmethodAsExternalCommand(null, null, iface.DCMTKpath + "\\img2dcm.exe", args); } else { // do the conversion pdf --> dcm; this is a local command, no ip/port needed for this one. wrapDCMTKmethodAsExternalCommand(null, null, iface.DCMTKpath + "\\pdf2dcm.exe", args); } if (!File.Exists(dcmFilename)) { Logger.Instance.WriteToLog("Send2PACS: Unable to convert JPG or PDF to DCM OR perhaps just unable to write it to disk. Check lkp_AutomationDocuments, lkpInterfaceDefinitions, document storage location and DICOM binary library (" + iface.DCMTKpath + ") for existence and/or permissions. Filename: " + dcmFilename + "."); continue; // something went wrong, but didn't throw an error... } // I'm guessing that we'll be adding a study/series ID later, just add another TripleArg here, if you didn't build the DCM with it in the metadata initially // If you need to fetch the UID, here is a sample of what a findscu would look like... don't forget the -aec and -aet... // findscu localhost 5678 -S -k StudyInstanceUID -k QueryRetrieveLevel=STUDY -k AccessionNumber=22222893 -aet Hughes -aec Hughes2 // and of course, you have to read the resulting array list. args.Clear(); TripleArg modArg0 = new TripleArg(); // dcm file name modArg0.ArgSwitch = "\"" + dcmFilename + "\""; args.Add(modArg0); if (!String.IsNullOrEmpty(accessionNumber)) { TripleArg modArg1 = new TripleArg(); // accession number modArg1.ArgSwitch = "-m"; modArg1.Name = "AccessionNumber"; // DICOM literal string, do not modify modArg1.Value = accessionNumber; args.Add(modArg1); } else { // make a note of this circumstance, it's especially critical for FMH Logger.Instance.WriteToLog("Send2PACS: Accession number is not set for Interface #" + iface.InterfaceId + " for appt # : " + apptId.ToString()); } TripleArg modArg2 = new TripleArg(); // Modality hard-coded to "OT". May need to be parameterized later. modArg2.ArgSwitch = "-i"; modArg2.Name = "Modality"; // DICOM literal string, do not modify modArg2.Value = iface.Modality; // "OT"; no longer hard-coded jdg 1/21/16 args.Add(modArg2); TripleArg modArg3 = new TripleArg(); // Patient Name modArg3.ArgSwitch = "-m"; modArg3.Name = "PatientName"; // DICOM literal string, do not modify patientname = patientname.Replace(", ", ","); // hack for extra space in name... patientname = patientname.Replace(", ", ","); // hack for extra space in name... modArg3.Value = "\"" + patientname.Replace(",", "^") + "\""; args.Add(modArg3); try { if (!String.IsNullOrEmpty(dob)) { dob = DateTime.ParseExact(dob, "MM/dd/yyyy", CultureInfo.InvariantCulture).ToString("yyyyMMdd"); // FMH preferred format... DICOM Standard?? } } catch (Exception) { } // else use dob as found in database TripleArg modArg4 = new TripleArg(); // Date of Birth modArg4.ArgSwitch = "-m"; modArg4.Name = "PatientBirthDate"; // DICOM literal string, do not modify modArg4.Value = dob; args.Add(modArg4); TripleArg modArg5 = new TripleArg(); // Gender modArg5.ArgSwitch = "-m"; modArg5.Name = "PatientSex"; // DICOM literal string, do not modify modArg5.Value = gender; args.Add(modArg5); try { if (!String.IsNullOrEmpty(apptDate)) { apptDate = DateTime.ParseExact(apptDate, "MM/dd/yyyy", CultureInfo.InvariantCulture).ToString("yyyyMMdd"); } } catch (Exception) { } // else use apptDate as found in database TripleArg modArg6 = new TripleArg(); // Study Date modArg6.ArgSwitch = "-m"; modArg6.Name = "StudyDate"; // DICOM literal string, do not modify modArg6.Value = apptDate; args.Add(modArg6); if ((iface.PacsSubType == (int)pacsSubTypes.JPG) || (iface.PacsSubType == (int)pacsSubTypes.BMP)) // pdf already has this in the metadata; img2dcm won't take patient id argument like pdf2dcm, for reasons that escape me { TripleArg modArg7 = new TripleArg(); // MRN modArg7.ArgSwitch = "-m"; modArg7.Name = "PatientID"; // DICOM literal string, do not modify modArg7.Value = patient.unitnum; args.Add(modArg7); } try { if (!String.IsNullOrEmpty(apptTime)) { apptTime = DateTime.ParseExact(apptTime, "hh:mm tt", CultureInfo.InvariantCulture).ToString("hhmm") + "00"; TripleArg modArg8 = new TripleArg(); // Date of Birth modArg8.ArgSwitch = "-m"; modArg8.Name = "StudyTime"; // DICOM literal string, do not modify modArg8.Value = apptTime; args.Add(modArg8); } } catch (Exception) { } // no time? no big deal. TripleArg modArg9 = new TripleArg(); // Study ID modArg9.ArgSwitch = "-m"; modArg9.Name = "StudyID"; // DICOM literal string, do not modify //modArg9.Value = "1"; modArg9.Value = iface.InterfaceId.ToString(); args.Add(modArg9); TripleArg modArg10 = new TripleArg(); // Series ID modArg10.ArgSwitch = "-m"; modArg10.Name = "SeriesNumber"; // DICOM literal string, do not modify //modArg10.Value = "1"; modArg10.Value = iface.InterfaceId.ToString(); args.Add(modArg10); TripleArg modArg11 = new TripleArg(); // Instance modArg11.ArgSwitch = "-m"; modArg11.Name = "InstanceNumber"; // DICOM literal string, do not modify //modArg11.Value = "1"; modArg11.Value = iface.InterfaceId.ToString(); args.Add(modArg11); wrapDCMTKmethodAsExternalCommand(null, null, iface.DCMTKpath + "\\dcmodify.exe", args); args.Clear(); TripleArg sendArg1 = new TripleArg(); // file to xmit sendArg1.ArgSwitch = "\"" + dcmFilename + "\""; args.Add(sendArg1); TripleArg sendArg2 = new TripleArg(); // ae title HRA sendArg2.ArgSwitch = "-aet"; sendArg2.Name = iface.AeTitleLocal; args.Add(sendArg2); TripleArg sendArg3 = new TripleArg(); // ae title remote sendArg3.ArgSwitch = "-aec"; sendArg3.Name = iface.AeTitleRemote; args.Add(sendArg3); if (!String.IsNullOrEmpty(iface.AdditionalParams)) { TripleArg sendArg4 = new TripleArg(); // additional params sendArg4.ArgSwitch = iface.AdditionalParams; args.Add(sendArg4); } // Send it out... finally! dicomOutputArgs = wrapDCMTKmethodAsExternalCommand(iface.IpAddress, iface.Port, iface.DCMTKpath + "\\storescu.exe", args); // todo: parse out any useful returned values... in the meantime, unless an error is thrown we'll return success Logger.Instance.WriteToLog("Send2PACS: Successful send to " + iface.AeTitleRemote + " for Interface #" + iface.InterfaceId + " " + (apptId > 0 ? " for appt id " + apptId.ToString() : "")); try { File.Delete(dcmFilename); // no point in keeping these around. File.Delete(dcmFilename + ".bak"); File.Delete(filename); } catch (Exception e) { Logger.Instance.WriteToLog("Send2PACS: Unable to delete " + dcmFilename + ", underlying error was " + e.Message); } } } // if some interfaces were processed, return true. if (interfaces.Count > 0) return true; else return false; }
/// <summary> /// Send the PDF document referenced by "dt" to the PACS system defined in the database lkpInterfaceDefinitions for this document /// </summary> /// <param name="dt">Document Template, as per the HTML document generation</param> /// <param name="patient">V3 Patient object</param> /// <param name="filename">Name of the PDF file to be converted to a .DCM (DICOM) file and transmitted to PACS</param> /// <param name="apptId">Appointment ID</param> /// <returns></returns> public static bool send2PACS(DocumentTemplate dt, RiskApps3.Model.PatientRecord.Patient patient, string filenameIn, int apptId) { List <TripleArg> args = new List <TripleArg>(); // for want of a tuple which doesn't exist till .NET 4.0 List <KeyValuePair <string, string> > dicomOutputArgs = new List <KeyValuePair <string, string> >(); List <InterfaceInstance> interfaces = new List <InterfaceInstance>(); //int interfaceId = -1; //string interfaceType = ""; //string ipAddress = ""; //string port = ""; //string aeTitleRemote = ""; //string aeTitleLocal = ""; //string DCMTKpath = ""; string accessionNumber = ""; string patientname = ""; string dob = ""; string gender = ""; string apptDate = ""; string apptTime = ""; //int pacsSubType = (int)pacsSubTypes.PDF; // NEW jdg 8/7/15... which type of encapsulated DCM to generate? Default to PDF... NOW 2 ==> JPG ParameterCollection pacsArgs = new ParameterCollection(); pacsArgs.Add("documentTemplateID", dt.documentTemplateID); string filename; SqlDataReader reader = BCDB2.Instance.ExecuteReaderSPWithParams("sp_getInterfaceDefinitionFromTemplateID", pacsArgs); while (reader.Read()) { InterfaceInstance instance = new InterfaceInstance(); if (reader.IsDBNull(0) == false) { instance.InterfaceId = reader.GetInt32(0); } if (reader.IsDBNull(1) == false) { instance.InterfaceType = reader.GetString(1); } if (reader.IsDBNull(2) == false) { instance.IpAddress = reader.GetString(2); } if (reader.IsDBNull(3) == false) { instance.Port = reader.GetString(3); } if (reader.IsDBNull(4) == false) { instance.AeTitleRemote = reader.GetString(4); } if (reader.IsDBNull(5) == false) { instance.AeTitleLocal = reader.GetString(5); } if (reader.IsDBNull(6) == false) { instance.DCMTKpath = reader.GetString(6); } if (reader.IsDBNull(7) == false) { instance.PacsSubType = reader.GetInt32(7); // for now, 1 == PDF, 2 == JPG, 3 == BMP (see enum pacsSubTypes, above) } if (instance.InterfaceId > 0) { interfaces.Add(instance); // multiple PACS interfaces per document are now supported. } } // just do this once... if (apptId > 0) { // This is an FMH specific hack, they are sending the Accession Number in the HL7 ADT_A08 message in PID|26... // and it is being stored in the appointment table in the unused field "referral". // No more obvious way of accomplishing this has jumped out at me yet, but this will have to be made more generic as new // customers are brought on-line. string sqlStr = "SELECT referral,patientname,dob,gender,apptDate,apptTime FROM tblAppointments WHERE apptID=" + apptId.ToString() + ";"; reader = BCDB2.Instance.ExecuteReader(sqlStr); while (reader.Read()) { if (reader.IsDBNull(0) == false) { accessionNumber = reader.GetString(0); } if (reader.IsDBNull(1) == false) // taking this from appointment table, alternatively, could use Patient object { patientname = reader.GetString(1); } if (reader.IsDBNull(2) == false) { dob = reader.GetString(2); } if (reader.IsDBNull(3) == false) { gender = reader.GetString(3); } if (reader.IsDBNull(4) == false) { apptDate = reader.GetString(4); } if (reader.IsDBNull(5) == false) { apptTime = reader.GetString(5); } } reader.Close(); } foreach (InterfaceInstance iface in interfaces) // send document to each eligible interface, converting it as need be { if ((iface.InterfaceId > 0) && (iface.InterfaceType == "PACS")) // no interface? not a PACS interface? bye bye! { // Ok! We're sending this thing to PACS... go ahead and convert the PDF file to a DCM file... // This will call into the DCMTK library to do their pdf2dcm, dcmodify (to set metadata), and storescu. Add appropriate parameters to the DCM. filename = filenameIn; // reinit // filter out oddball cases of calling this method with conflicting interface parameters versus the type of file passed in. // however, we WILL reconvert PDFs to an image upon demand, see below. if (((filename.ToUpper().Contains(".JPG")) || (filename.ToUpper().Contains(".BMP"))) && (iface.PacsSubType == (int)pacsSubTypes.PDF)) { Logger.Instance.WriteToLog("Send2PACS: Attempted to send an image file to a PDF interface, interfaceID #" + iface.InterfaceId + ". Request Aborted" + (apptId > 0 ? " for appt id " + apptId.ToString() + "." : ".")); continue; } if (iface.PacsSubType == (int)pacsSubTypes.JPG) // jpg { // If we were sent a PDF file, yet it's pacsSubType is different, convert the document to an image // this could happen depending on what type of file is generated from the survey, and the settings made in lkpInterfaceDefinitions // as of now, we're not converting between jpgs and bmps... if you send a bmp and interface type is jpg, bail... and vice versa if (filename.ToUpper().Contains(".BMP")) { Logger.Instance.WriteToLog("Send2PACS: Attempted to send a BMP file to a JPG interface. Request Aborted" + (apptId > 0 ? " for appt id " + apptId.ToString() + "." : ".")); continue; } if (filename.ToUpper().Contains(".PDF")) // re-convert this html to an image instead { HtmlToImageConverter htmlToJpgConverter = new HtmlToImageConverter(); htmlToJpgConverter.LicenseKey = "sjwvPS4uPSskPSgzLT0uLDMsLzMkJCQk"; filename = filename.ToUpper().Replace(".PDF", "") + ".jpg"; htmlToJpgConverter.ConvertHtmlToFile(dt.htmlText, "", System.Drawing.Imaging.ImageFormat.Jpeg, filename); } } if (iface.PacsSubType == (int)pacsSubTypes.BMP) // bitmap { // If we were sent a PDF file, yet it's pacsSubType is different, convert the document to an image // this could happen depending on what type of file is generated from the survey, and the settings made in lkpInterfaceDefinitions // as of now, we're not converting between jpgs and bmps... if you send a bmp and interface type is jpg, bail... and vice versa if (filename.ToUpper().Contains(".JPG")) { Logger.Instance.WriteToLog("Send2PACS: Attempted to send a JPG file to a BMP interface. Request Aborted" + (apptId > 0 ? " for appt id " + apptId.ToString() + "." : ".")); continue; } if (filename.ToUpper().Contains(".PDF")) // re-convert this html to an image instead { HtmlToImageConverter htmlToJpgConverter = new HtmlToImageConverter(); htmlToJpgConverter.LicenseKey = "sjwvPS4uPSskPSgzLT0uLDMsLzMkJCQk"; filename = filename.ToUpper().Replace(".PDF", "") + ".bmp"; htmlToJpgConverter.ConvertHtmlToFile(dt.htmlText, "", System.Drawing.Imaging.ImageFormat.Bmp, filename); } } args.Clear(); string dcmFilename = filename + ".dcm"; TripleArg arg1 = new TripleArg(); //arg1.ArgSwitch = filename; arg1.ArgSwitch = "\"" + filename + "\""; args.Add(arg1); TripleArg arg2 = new TripleArg(); //arg2.ArgSwitch = dcmFilename; arg2.ArgSwitch = "\"" + dcmFilename + "\""; args.Add(arg2); if ((patient != null) && (iface.PacsSubType == (int)pacsSubTypes.PDF)) // for some reason, img2dcm (jpg) doesn't have a patient identifier arg. will have to insert this into the metadata later. { TripleArg arg3 = new TripleArg(); arg3.ArgSwitch = "+pi"; arg3.Name = patient.unitnum; args.Add(arg3); } if (iface.PacsSubType == (int)pacsSubTypes.BMP) // defaults to jpg { TripleArg arg4 = new TripleArg(); arg4.ArgSwitch = "-i"; arg4.Name = "BMP"; args.Add(arg4); } if ((iface.PacsSubType == (int)pacsSubTypes.JPG) || (iface.PacsSubType == (int)pacsSubTypes.BMP)) // jpg, bmp { // do the conversion jpg --> dcm; this is a local command, no ip/port needed for this one. wrapDCMTKmethodAsExternalCommand(null, null, iface.DCMTKpath + "\\img2dcm.exe", args); } else { // do the conversion pdf --> dcm; this is a local command, no ip/port needed for this one. wrapDCMTKmethodAsExternalCommand(null, null, iface.DCMTKpath + "\\pdf2dcm.exe", args); } if (!File.Exists(dcmFilename)) { Logger.Instance.WriteToLog("Send2PACS: Unable to convert JPG or PDF to DCM OR perhaps just unable to write it to disk. Check lkp_AutomationDocuments, lkpInterfaceDefinitions, document storage location and DICOM binary library (" + iface.DCMTKpath + ") for existence and/or permissions. Filename: " + dcmFilename + "."); continue; // something went wrong, but didn't throw an error... } // I'm guessing that we'll be adding a study/series ID later, just add another TripleArg here, if you didn't build the DCM with it in the metadata initially // If you need to fetch the UID, here is a sample of what a findscu would look like... don't forget the -aec and -aet... // findscu localhost 5678 -S -k StudyInstanceUID -k QueryRetrieveLevel=STUDY -k AccessionNumber=22222893 -aet Hughes -aec Hughes2 // and of course, you have to read the resulting array list. args.Clear(); TripleArg modArg0 = new TripleArg(); // dcm file name modArg0.ArgSwitch = "\"" + dcmFilename + "\""; args.Add(modArg0); if (!String.IsNullOrEmpty(accessionNumber)) { TripleArg modArg1 = new TripleArg(); // accession number modArg1.ArgSwitch = "-m"; modArg1.Name = "AccessionNumber"; // DICOM literal string, do not modify modArg1.Value = accessionNumber; args.Add(modArg1); } else { // make a note of this circumstance, it's especially critical for FMH Logger.Instance.WriteToLog("Send2PACS: Accession number is not set for Interface #" + iface.InterfaceId + " for appt # : " + apptId.ToString()); } TripleArg modArg2 = new TripleArg(); // Modality hard-coded to "OT". May need to be parameterized later. modArg2.ArgSwitch = "-i"; modArg2.Name = "Modality"; // DICOM literal string, do not modify modArg2.Value = "OT"; args.Add(modArg2); TripleArg modArg3 = new TripleArg(); // Patient Name modArg3.ArgSwitch = "-m"; modArg3.Name = "PatientName"; // DICOM literal string, do not modify patientname = patientname.Replace(", ", ","); // hack for extra space in name... patientname = patientname.Replace(", ", ","); // hack for extra space in name... modArg3.Value = patientname.Replace(",", "^"); args.Add(modArg3); try { if (!String.IsNullOrEmpty(dob)) { dob = DateTime.ParseExact(dob, "MM/dd/yyyy", CultureInfo.InvariantCulture).ToString("yyyyMMdd"); // FMH preferred format... DICOM Standard?? } } catch (Exception) { } // else use dob as found in database TripleArg modArg4 = new TripleArg(); // Date of Birth modArg4.ArgSwitch = "-m"; modArg4.Name = "PatientBirthDate"; // DICOM literal string, do not modify modArg4.Value = dob; args.Add(modArg4); TripleArg modArg5 = new TripleArg(); // Gender modArg5.ArgSwitch = "-m"; modArg5.Name = "PatientSex"; // DICOM literal string, do not modify modArg5.Value = gender; args.Add(modArg5); try { if (!String.IsNullOrEmpty(apptDate)) { apptDate = DateTime.ParseExact(apptDate, "MM/dd/yyyy", CultureInfo.InvariantCulture).ToString("yyyyMMdd"); } } catch (Exception) { } // else use apptDate as found in database TripleArg modArg6 = new TripleArg(); // Study Date modArg6.ArgSwitch = "-m"; modArg6.Name = "StudyDate"; // DICOM literal string, do not modify modArg6.Value = apptDate; args.Add(modArg6); if ((iface.PacsSubType == (int)pacsSubTypes.JPG) || (iface.PacsSubType == (int)pacsSubTypes.BMP)) // pdf already has this in the metadata; img2dcm won't take patient id argument like pdf2dcm, for reasons that escape me { TripleArg modArg7 = new TripleArg(); // MRN modArg7.ArgSwitch = "-m"; modArg7.Name = "PatientID"; // DICOM literal string, do not modify modArg7.Value = patient.unitnum; args.Add(modArg7); } try { if (!String.IsNullOrEmpty(apptTime)) { apptTime = DateTime.ParseExact(apptTime, "hh:mm tt", CultureInfo.InvariantCulture).ToString("hhmm") + "00"; TripleArg modArg8 = new TripleArg(); // Date of Birth modArg8.ArgSwitch = "-m"; modArg8.Name = "StudyTime"; // DICOM literal string, do not modify modArg8.Value = apptTime; args.Add(modArg8); } } catch (Exception) { } // no time? no big deal. TripleArg modArg9 = new TripleArg(); // Study ID modArg9.ArgSwitch = "-m"; modArg9.Name = "StudyID"; // DICOM literal string, do not modify //modArg9.Value = "1"; modArg9.Value = iface.InterfaceId.ToString(); args.Add(modArg9); TripleArg modArg10 = new TripleArg(); // Series ID modArg10.ArgSwitch = "-m"; modArg10.Name = "SeriesNumber"; // DICOM literal string, do not modify //modArg10.Value = "1"; modArg10.Value = iface.InterfaceId.ToString(); args.Add(modArg10); TripleArg modArg11 = new TripleArg(); // Instance modArg11.ArgSwitch = "-m"; modArg11.Name = "InstanceNumber"; // DICOM literal string, do not modify //modArg11.Value = "1"; modArg11.Value = iface.InterfaceId.ToString(); args.Add(modArg11); wrapDCMTKmethodAsExternalCommand(null, null, iface.DCMTKpath + "\\dcmodify.exe", args); args.Clear(); TripleArg sendArg1 = new TripleArg(); // file to xmit sendArg1.ArgSwitch = "\"" + dcmFilename + "\""; args.Add(sendArg1); TripleArg sendArg2 = new TripleArg(); // ae title HRA sendArg2.ArgSwitch = "-aet"; sendArg2.Name = iface.AeTitleLocal; args.Add(sendArg2); TripleArg sendArg3 = new TripleArg(); // ae title remote sendArg3.ArgSwitch = "-aec"; sendArg3.Name = iface.AeTitleRemote; args.Add(sendArg3); // Send it out... finally! dicomOutputArgs = wrapDCMTKmethodAsExternalCommand(iface.IpAddress, iface.Port, iface.DCMTKpath + "\\storescu.exe", args); // todo: parse out any useful returned values... in the meantime, unless an error is thrown we'll return success Logger.Instance.WriteToLog("Send2PACS: Successful send to " + iface.AeTitleRemote + " for Interface #" + iface.InterfaceId + " " + (apptId > 0 ? " for appt id " + apptId.ToString() : "")); try { File.Delete(dcmFilename); // no point in keeping these around. File.Delete(dcmFilename + ".bak"); File.Delete(filename); } catch (Exception e) { Logger.Instance.WriteToLog("Send2PACS: Unable to delete " + dcmFilename + ", underlying error was " + e.Message); } } } // if some interfaces were processed, return true. if (interfaces.Count > 0) { return(true); } else { return(false); } }