Dicom Printer

Created Diff never expires
7 removals
Words removed8
Total words860
Words removed (%)0.93
334 lines
27 additions
Words added51
Total words903
Words added (%)5.65
354 lines
using System;
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Imaging;
using System.Threading.Tasks;
using System.Threading.Tasks;
using FellowOakDicom;
using FellowOakDicom;
using FellowOakDicom.Imaging;
using FellowOakDicom.Imaging;
using FellowOakDicom.IO;
using FellowOakDicom.IO;
using FellowOakDicom.Network;
using FellowOakDicom.Network;
using FellowOakDicom.Printing;
using FellowOakDicom.Printing;
using FellowOakDicom.Network.Client;
using FellowOakDicom.Network.Client;
using FellowOakDicom.IO.Buffer;
using FellowOakDicom.IO.Buffer;
using System.IO;
using System.IO;
using System.Printing;


namespace libd2print
namespace libd2print
{
{


internal class DicomPrinter
internal class DicomPrinter
{
{
private static DicomPrinter _instance;
private static DicomPrinter _instance;


public static DicomPrinter I
public static DicomPrinter I
{
{
get
get
{
{
if (_instance == null)
if (_instance == null)
{
{
_instance = new DicomPrinter();
_instance = new DicomPrinter();
}
}
return _instance;
return _instance;
}
}


}
}


public async Task Print(string RemoteAddress, int RemotePort, string CallingAE, string CalledAE, string FullPrintJobFolder, int pages)
public async Task Print(string RemoteAddress, int RemotePort, string CallingAE, string CalledAE, string FullPrintJobFolder, int pages)
{
{
var printJob = new PrintJobDicom("DICOM PRINT JOB", "BLUE FILM")
var printJob = new PrintJobDicom("DICOM PRINT JOB", "BLUE FILM")
{
{
RemoteAddress = RemoteAddress,
RemoteAddress = RemoteAddress,
RemotePort = RemotePort,
RemotePort = RemotePort,
CallingAE = CallingAE,// printscu
CallingAE = CallingAE,// print scu
CalledAE = CalledAE //print scp
CalledAE = CalledAE //print scp
};
};


//greyscale
//greyscale


var testPath = Path.Combine(FullPrintJobFolder);
var testPath = Path.Combine(FullPrintJobFolder);
//var greyscaleImg = new DicomImage(testPath + "/I000001.dcm");
//var greyscaleImg = new DicomImage(testPath + "/I000001.dcm");


var i = 0;
var i = 0;
while (i < pages)
while (i < pages)
{
{
Image Dummy = Image.FromFile(testPath + "/" + (i + 1).ToString() + ".png");
Image Dummy = Image.FromFile(testPath + "/" + (i + 1).ToString() + ".png");
using (var dum = Dummy)
using (var dum = Dummy)
{
{
Bitmap bmp = new Bitmap(dum);
Bitmap bmp = new Bitmap(dum);
using (var bitmap = bmp)
using (var bitmap = bmp)
{
{
printJob.FilmSession.IsColor = false; //set to true to print in color
printJob.FilmSession.IsColor = false; //set to true to print in color
printJob.StartFilmBox("STANDARD\\1,1", "PORTRAIT", "10INX14IN", "BILINEAR");
printJob.StartFilmBox("STANDARD\\1,1", "PORTRAIT", "8INX10IN", "CUBIC");
printJob.AddImage(bitmap, 0);
printJob.AddImage(bitmap, 0);
}
}
}
}
i++;
i++;
}
}
printJob.EndFilmBox();
printJob.EndFilmBox();




await printJob.Print();
await printJob.Print();
}
}
}
}


internal class PrintJobDicom
internal class PrintJobDicom
{
{
public string CallingAE { get; set; }
public string CallingAE { get; set; }
public string CalledAE { get; set; }
public string CalledAE { get; set; }
public string RemoteAddress { get; set; }
public string RemoteAddress { get; set; }
public int RemotePort { get; set; }
public int RemotePort { get; set; }


public FilmSession FilmSession { get; private set; }
public FilmSession FilmSession { get; private set; }


private FilmBox _currentFilmBox;
private FilmBox _currentFilmBox;


public PrintJobDicom(string jobLabel, string mediumType = "PAPER")
public PrintJobDicom(string jobLabel, string mediumType = "PAPER")
{
{
FilmSession = new FilmSession(DicomUID.BasicFilmSession)
FilmSession = new FilmSession(DicomUID.BasicFilmSession)
{
{
FilmSessionLabel = jobLabel,
FilmSessionLabel = jobLabel,
MediumType = mediumType,
MediumType = mediumType,
NumberOfCopies = 1
NumberOfCopies = 1,
PrintPriority = "MED",
FilmDestination = "BIN_1",
};
};

FilmSession.FilmSessionLabel = "";
}
}


public FilmBox StartFilmBox(string format, string orientation, string filmSize, string magnificationType = "NONE")
public FilmBox StartFilmBox(string format, string orientation, string filmSize, string magnificationType = "NONE")
{
{
var filmBox = new FilmBox(FilmSession, null, DicomTransferSyntax.ExplicitVRLittleEndian)
var filmBox = new FilmBox(FilmSession, null, DicomTransferSyntax.ExplicitVRLittleEndian)
{
{
ImageDisplayFormat = format,
ImageDisplayFormat = format,
FilmOrientation = orientation,
FilmOrientation = orientation,
FilmSizeID = filmSize,
FilmSizeID = filmSize,
MagnificationType = magnificationType,
MagnificationType = magnificationType,
BorderDensity = "WHITE",
BorderDensity = "WHITE",
EmptyImageDensity = "BLACK",
//EmptyImageDensity = "BLACK",
Trim = "YES"
//Trim = "YES"
};
};


filmBox.AnnotationDisplayFormatID = "0";
filmBox.SmoothingType = "5";
filmBox.Illumination = 2000;
filmBox.ReflectedAmbientLight = 10;
filmBox.Trim = "NO";


filmBox.Initialize();
filmBox.Initialize();
FilmSession.BasicFilmBoxes.Add(filmBox);
FilmSession.BasicFilmBoxes.Add(filmBox);


_currentFilmBox = filmBox;
_currentFilmBox = filmBox;
return filmBox;
return filmBox;
}
}


public void AddImage(Bitmap bitmap, int index)
public void AddImage(Bitmap bitmap, int index)
{
{
if (FilmSession.IsColor)
if (FilmSession.IsColor)
{
{
AddColorImage(bitmap, index);
AddColorImage(bitmap, index);
}
}
else
else
{
{
AddGreyscaleImage(bitmap, index);
AddGreyscaleImage(bitmap, index);
}
}
}
}


private void AddGreyscaleImage(Bitmap bitmap, int index)
private void AddGreyscaleImage(Bitmap bitmap, int index)
{
{
if (_currentFilmBox == null)
if (_currentFilmBox == null)
{
{
throw new InvalidOperationException("Start film box first!");
throw new InvalidOperationException("Start film box first!");
}
}
if (index < 0 || index > _currentFilmBox.BasicImageBoxes.Count)
if (index < 0 || index > _currentFilmBox.BasicImageBoxes.Count)
{
{
throw new ArgumentOutOfRangeException(nameof(index), "Image box index out of range");
throw new ArgumentOutOfRangeException(nameof(index), "Image box index out of range");
}
}


if (bitmap.PixelFormat != PixelFormat.Format24bppRgb && bitmap.PixelFormat != PixelFormat.Format32bppArgb
if (bitmap.PixelFormat != PixelFormat.Format24bppRgb && bitmap.PixelFormat != PixelFormat.Format32bppArgb
&& bitmap.PixelFormat != PixelFormat.Format32bppRgb)
&& bitmap.PixelFormat != PixelFormat.Format32bppRgb)
{
{
throw new ArgumentException("Not supported bitmap format", nameof(bitmap));
throw new ArgumentException("Not supported bitmap format", nameof(bitmap));
}
}


var dataset = new DicomDataset();
var dataset = new DicomDataset();
dataset.Add<ushort>(DicomTag.Columns, (ushort)bitmap.Width)
dataset.Add<ushort>(DicomTag.Columns, (ushort)bitmap.Width)
.Add<ushort>(DicomTag.Rows, (ushort)bitmap.Height)
.Add<ushort>(DicomTag.Rows, (ushort)bitmap.Height)
.Add<ushort>(DicomTag.BitsAllocated, 8)
.Add<ushort>(DicomTag.BitsAllocated, 8)
.Add<ushort>(DicomTag.BitsStored, 8)
.Add<ushort>(DicomTag.BitsStored, 8)
.Add<ushort>(DicomTag.HighBit, 7)
.Add<ushort>(DicomTag.HighBit, 7)
.Add(DicomTag.PixelRepresentation, (ushort)PixelRepresentation.Unsigned)
.Add(DicomTag.PixelRepresentation, (ushort)PixelRepresentation.Unsigned)
.Add(DicomTag.PlanarConfiguration, (ushort)PlanarConfiguration.Interleaved)
.Add(DicomTag.PlanarConfiguration, (ushort)PlanarConfiguration.Interleaved)
.Add<ushort>(DicomTag.SamplesPerPixel, 1)
.Add<ushort>(DicomTag.SamplesPerPixel, 1)//OK
.Add(DicomTag.PhotometricInterpretation, PhotometricInterpretation.Rgb.Value);
.Add(DicomTag.PhotometricInterpretation, PhotometricInterpretation.Monochrome2);
dataset.Add(DicomTag.PixelAspectRatio, 1);
dataset.Add(DicomTag.PixelRepresentation, "0000H");
dataset.Add(DicomTag.Polarity, "NORMAL");
dataset.Add(DicomTag.MagnificationType, "CUBIC");
dataset.Add(DicomTag.SmoothingType, 5);
dataset.Add(DicomTag.ConfigurationInformation, "LUT=Ver693c0.w87,6");
dataset.Add(DicomTag.RequestedImageSize, "0.00");
dataset.Add(DicomTag.RequestedDecimateCropBehavior, "DECIMATE");


var pixelData = DicomPixelData.Create(dataset, true);
var pixelData = DicomPixelData.Create(dataset, true);


var pixels = GetGreyBytes(bitmap);
var pixels = GetGreyBytes(bitmap);
var buffer = new MemoryByteBuffer(pixels.Data);
var buffer = new MemoryByteBuffer(pixels.Data);


pixelData.AddFrame(buffer);
pixelData.AddFrame(buffer);


var imageBox = _currentFilmBox.BasicImageBoxes[index];
var imageBox = _currentFilmBox.BasicImageBoxes[index];
imageBox.ImageSequence = dataset;
imageBox.ImageSequence = dataset;


pixels.Dispose();
pixels.Dispose();
}
}


private void AddColorImage(Bitmap bitmap, int index)
private void AddColorImage(Bitmap bitmap, int index)
{
{
if (_currentFilmBox == null)
if (_currentFilmBox == null)
{
{
throw new InvalidOperationException("Start film box first!");
throw new InvalidOperationException("Start film box first!");
}
}
if (index < 0 || index > _currentFilmBox.BasicImageBoxes.Count)
if (index < 0 || index > _currentFilmBox.BasicImageBoxes.Count)
{
{
throw new ArgumentOutOfRangeException(nameof(index), "Image box index out of range");
throw new ArgumentOutOfRangeException(nameof(index), "Image box index out of range");
}
}


if (bitmap.PixelFormat != PixelFormat.Format24bppRgb && bitmap.PixelFormat != PixelFormat.Format32bppArgb
if (bitmap.PixelFormat != PixelFormat.Format24bppRgb && bitmap.PixelFormat != PixelFormat.Format32bppArgb
&& bitmap.PixelFormat != PixelFormat.Format32bppRgb)
&& bitmap.PixelFormat != PixelFormat.Format32bppRgb)
{
{
throw new ArgumentException("Not supported bitmap format", nameof(bitmap));
throw new ArgumentException("Not supported bitmap format", nameof(bitmap));
}
}


var dataset = new DicomDataset();
var dataset = new DicomDataset();
dataset.Add<ushort>(DicomTag.Columns, (ushort)bitmap.Width)
dataset.Add<ushort>(DicomTag.Columns, (ushort)bitmap.Width)
.Add<ushort>(DicomTag.Rows, (ushort)bitmap.Height)
.Add<ushort>(DicomTag.Rows, (ushort)bitmap.Height)
.Add<ushort>(DicomTag.BitsAllocated, 8)
.Add<ushort>(DicomTag.BitsAllocated, 8)
.Add<ushort>(DicomTag.BitsStored, 8)
.Add<ushort>(DicomTag.BitsStored, 8)
.Add<ushort>(DicomTag.HighBit, 7)
.Add<ushort>(DicomTag.HighBit, 7)
.Add(DicomTag.PixelRepresentation, (ushort)PixelRepresentation.Unsigned)
.Add(DicomTag.PixelRepresentation, (ushort)PixelRepresentation.Unsigned)
.Add(DicomTag.PlanarConfiguration, (ushort)PlanarConfiguration.Interleaved)
.Add(DicomTag.PlanarConfiguration, (ushort)PlanarConfiguration.Interleaved)
.Add<ushort>(DicomTag.SamplesPerPixel, 3)
.Add<ushort>(DicomTag.SamplesPerPixel, 3)
.Add(DicomTag.PhotometricInterpretation, PhotometricInterpretation.Rgb.Value);
.Add(DicomTag.PhotometricInterpretation, PhotometricInterpretation.Rgb.Value);


var pixelData = DicomPixelData.Create(dataset, true);
var pixelData = DicomPixelData.Create(dataset, true);


var pixels = GetColorbytes(bitmap);
var pixels = GetColorbytes(bitmap);
var buffer = new MemoryByteBuffer(pixels.Data);
var buffer = new MemoryByteBuffer(pixels.Data);


pixelData.AddFrame(buffer);
pixelData.AddFrame(buffer);


var imageBox = _currentFilmBox.BasicImageBoxes[index];
var imageBox = _currentFilmBox.BasicImageBoxes[index];
imageBox.ImageSequence = dataset;
imageBox.ImageSequence = dataset;


pixels.Dispose();
pixels.Dispose();
}
}


public void EndFilmBox()
public void EndFilmBox()
{
{
_currentFilmBox = null;
_currentFilmBox = null;
}
}


public async Task Print()
public async Task Print()
{
{
var dicomClient = DicomClientFactory.Create(RemoteAddress, RemotePort, false, CallingAE, CalledAE);
var dicomClient = DicomClientFactory.Create(RemoteAddress, RemotePort, false, CallingAE, CalledAE);


await dicomClient.AddRequestAsync(
await dicomClient.AddRequestAsync(
new DicomNCreateRequest(FilmSession.SOPClassUID, FilmSession.SOPInstanceUID)
new DicomNCreateRequest(FilmSession.SOPClassUID, FilmSession.SOPInstanceUID)
{
{
Dataset = FilmSession
Dataset = FilmSession
});
});




foreach (var filmbox in FilmSession.BasicFilmBoxes)
foreach (var filmbox in FilmSession.BasicFilmBoxes)
{
{


var imageBoxRequests = new List<DicomNSetRequest>();
var imageBoxRequests = new List<DicomNSetRequest>();


var filmBoxRequest = new DicomNCreateRequest(FilmBox.SOPClassUID, filmbox.SOPInstanceUID)
var filmBoxRequest = new DicomNCreateRequest(FilmBox.SOPClassUID, filmbox.SOPInstanceUID)
{
{
Dataset = filmbox
Dataset = filmbox
};
};
filmBoxRequest.OnResponseReceived = (request, response) =>
filmBoxRequest.OnResponseReceived = (request, response) =>
{
{
if (response.HasDataset)
if (response.HasDataset)
{
{
var seq = response.Dataset.GetSequence(DicomTag.ReferencedImageBoxSequence);
var seq = response.Dataset.GetSequence(DicomTag.ReferencedImageBoxSequence);
for (int i = 0; i < seq.Items.Count; i++)
for (int i = 0; i < seq.Items.Count; i++)
{
{
var req = imageBoxRequests[i];
var req = imageBoxRequests[i];
var imageBox = req.Dataset;
var imageBox = req.Dataset;
var sopInstanceUid = seq.Items[i].GetSingleValue<string>(DicomTag.ReferencedSOPInstanceUID);
var sopInstanceUid = seq.Items[i].GetSingleValue<string>(DicomTag.ReferencedSOPInstanceUID);
imageBox.AddOrUpdate(DicomTag.SOPInstanceUID, sopInstanceUid);
imageBox.AddOrUpdate(DicomTag.SOPInstanceUID, sopInstanceUid);
req.Command.AddOrUpdate(DicomTag.RequestedSOPInstanceUID, sopInstanceUid);
req.Command.AddOrUpdate(DicomTag.RequestedSOPInstanceUID, sopInstanceUid);
}
}
}
}
};
};
await dicomClient.AddRequestAsync(filmBoxRequest);
await dicomClient.AddRequestAsync(filmBoxRequest);


foreach (var image in filmbox.BasicImageBoxes)
foreach (var image in filmbox.BasicImageBoxes)
{
{
var req = new DicomNSetRequest(image.SOPClassUID, image.SOPInstanceUID) { Dataset = image };
var req = new DicomNSetRequest(image.SOPClassUID, image.SOPInstanceUID) { Dataset = image };


imageBoxRequests.Add(req);
imageBoxRequests.Add(req);
await dicomClient.AddRequestAsync(req);
await dicomClient.AddRequestAsync(req);
}
}
}
}


await dicomClient.AddRequestAsync(new DicomNActionRequest(FilmSession.SOPClassUID, FilmSession.SOPInstanceUID, 0x0001));
await dicomClient.AddRequestAsync(new DicomNActionRequest(FilmSession.SOPClassUID, FilmSession.SOPInstanceUID, 0x0001));


await dicomClient.SendAsync();
await dicomClient.SendAsync();
}
}




private unsafe PinnedByteArray GetGreyBytes(Bitmap bitmap)
private unsafe PinnedByteArray GetGreyBytes(Bitmap bitmap)
{
{
var pixels = new PinnedByteArray(bitmap.Width * bitmap.Height);
var pixels = new PinnedByteArray(bitmap.Width * bitmap.Height);


var data = bitmap.LockBits(
var data = bitmap.LockBits(
new Rectangle(0, 0, bitmap.Width, bitmap.Height),
new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.ReadOnly,
ImageLockMode.ReadOnly,
bitmap.PixelFormat);
bitmap.PixelFormat);


var srcComponents = bitmap.PixelFormat == PixelFormat.Format24bppRgb ? 3 : 4;
var srcComponents = bitmap.PixelFormat == PixelFormat.Format24bppRgb ? 3 : 4;


var dstLine = (byte*)pixels.Pointer;
var dstLine = (byte*)pixels.Pointer;
var srcLine = (byte*)data.Scan0.ToPointer();
var srcLine = (byte*)data.Scan0.ToPointer();


for (int i = 0; i < data.Height; i++)
for (int i = 0; i < data.Height; i++)
{
{
for (int j = 0; j < data.Width; j++)
for (int j = 0; j < data.Width; j++)
{
{
var pixel = srcLine + j * srcComponents;
var pixel = srcLine + j * srcComponents;
int grey = (int)(pixel[0] * 0.3 + pixel[1] * 0.59 + pixel[2] * 0.11);
int grey = (int)(pixel[0] * 0.3 + pixel[1] * 0.59 + pixel[2] * 0.11);
dstLine[j] = (byte)grey;
dstLine[j] = (byte)grey;
}
}


srcLine += data.Stride;
srcLine += data.Stride;
dstLine += data.Width;
dstLine += data.Width;
}
}
bitmap.UnlockBits(data);
bitmap.UnlockBits(data);


return pixels;
return pixels;
}
}


private unsafe PinnedByteArray GetColorbytes(Bitmap bitmap)
private unsafe PinnedByteArray GetColorbytes(Bitmap bitmap)
{
{
var pixels = new PinnedByteArray(bitmap.Width * bitmap.Height * 3);
var pixels = new PinnedByteArray(bitmap.Width * bitmap.Height * 3);


var data = bitmap.LockBits(
var data = bitmap.LockBits(
new Rectangle(0, 0, bitmap.Width, bitmap.Height),
new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.ReadOnly,
ImageLockMode.ReadOnly,
bitmap.PixelFormat);
bitmap.PixelFormat);


var srcComponents = bitmap.PixelFormat == PixelFormat.Format24bppRgb ? 3 : 4;
var srcComponents = bitmap.PixelFormat == PixelFormat.Format24bppRgb ? 3 : 4;


var dstLine = (byte*)pixels.Pointer;
var dstLine = (byte*)pixels.Pointer;
var srcLine = (byte*)data.Scan0.ToPointer();
var srcLine = (byte*)data.Scan0.ToPointer();


for (int i = 0; i < data.Height; i++)
for (int i = 0; i < data.Height; i++)
{
{
for (int j = 0; j < data.Width; j++)
for (int j = 0; j < data.Width; j++)
{
{
var srcPixel = srcLine + j * srcComponents;
var srcPixel = srcLine + j * srcComponents;
var dstPixel = dstLine + j * 3;
var dstPixel = dstLine + j * 3;


//convert from bgr to rgb
//convert from bgr to rgb
dstPixel[0] = srcPixel[2];
dstPixel[0] = srcPixel[2];
dstPixel[1] = srcPixel[1];
dstPixel[1] = srcPixel[1];
dstPixel[2] = srcPixel[0];
dstPixel[2] = srcPixel[0];
}
}


srcLine += data.Stride;
srcLine += data.Stride;
dstLine += data.Width * 3;
dstLine += data.Width * 3;
}
}
bitmap.UnlockBits(data);
bitmap.UnlockBits(data);


return pixels;
return pixels;
}
}


}
}
}
}