It is a little bit of code but this is how I do it. This appears to be a common question with duplicates. I pieced this together over time from the Clear Canvas forums, but it is a completely valid answer to the question asked.
If it is needed to create DICOM Secondary Capture images from standard image files like jpg, and you desire for them to work correctly with all the PACS, VNA's, and other DICOM applications out there, then this code here works for that.
OK I have to edit one more time. This I pieced together for fun, I just needed to be able to do it. Some DICOM images I created I added to my test suite, but I had more fun with it than anything. I took the Homer Simpson brain picture and wrapped it. As well the 'When Radiologists take a selfie' picture. Not to forget the last one I did, there was a high quality picture of a X-Ray of a Moray eel in the news fairly recently, so I wrapped that one in DICOM too. Hence the example you see.
Ok even one more edit. Since writing this answer, I have discovered a very valuable ability with this code. I can generate pixel data in any fashion to test our product. Already I can generate DICOM images in Explicit Little Endian, at 10,000 X 10,000 pixels, and that can definitely cause problems in the DICOM products out there, but I can generate it with Clear Canvas without problems!
I can also send data using this code using simple small 5 x 5 pixel images, and it helps so much for testing to build large databases quickly, or ramp up certain backlogs. I only hope someone else finds this as useful as I have.
using ClearCanvas.Dicom.Codec;
using ClearCanvas.Common.Utilities;
using ClearCanvas.Dicom;
using ClearCanvas.Dicom.Network;
using ClearCanvas.Common;
using ClearCanvas.ImageViewer;
using ClearCanvas.ImageViewer.Imaging;
using ClearCanvas.ImageViewer.Graphics;
using ClearCanvas.ImageViewer.StudyManagement;
DicomFile df = null;
Bitmap bm = LoadImage(tbImageFile.Text);
CreateBaseDataSet();
df = ConvertImage(bm, 1);
df.Save(@"C:\test.dcm", DicomWriteOptions.Default);
Then here is all the rest of it:
private void CreateBaseDataSet()
{
_baseDataSet = new DicomAttributeCollection();
//Sop Common
_baseDataSet[DicomTags.SopClassUid].SetStringValue(SopClass.SecondaryCaptureImageStorageUid);
////Patient
//_baseDataSet[DicomTags.PatientId].SetStringValue(_parent.PatientId);
//_baseDataSet[DicomTags.PatientsName].SetStringValue(String.Format("{0}^{1}^{2}^^",
// _parent.LastName, _parent.FirstName, _parent.MiddleName));
//_baseDataSet[DicomTags.PatientsBirthDate].SetDateTime(0, _parent.Dob);
//_baseDataSet[DicomTags.PatientsSex].SetStringValue(_parent.Sex.ToString());
////Study
//_baseDataSet[DicomTags.StudyInstanceUid].SetStringValue(DicomUid.GenerateUid().UID);
//_baseDataSet[DicomTags.StudyDate].SetDateTime(0, _parent.StudyDate);
//_baseDataSet[DicomTags.StudyTime].SetDateTime(0, _parent.StudyTime);
//_baseDataSet[DicomTags.AccessionNumber].SetStringValue(_parent.AccessionNumber);
//_baseDataSet[DicomTags.StudyDescription].SetStringValue(_parent.StudyDescription);
//Patient
_baseDataSet[DicomTags.PatientId].SetStringValue("PIDEEL");
_baseDataSet[DicomTags.PatientsName].SetStringValue(String.Format("Moray^Eel^X-Ray"));
//_baseDataSet[DicomTags.PatientsAddress].SetString (0,"Hubertus");
//_baseDataSet[DicomTags.PatientsBirthDate].SetDateTime(0, DateTime.Now);
//_baseDataSet[DicomTags.PatientsBirthDate].SetString(0, "19550512");
_baseDataSet[DicomTags.PatientsSex].SetStringValue("O");
//Study
_baseDataSet[DicomTags.StudyInstanceUid].SetStringValue(DicomUid.GenerateUid().UID);
_baseDataSet[DicomTags.StudyDate].SetDateTime(0, DateTime.Now);
_baseDataSet[DicomTags.StudyTime].SetDateTime(0, DateTime.Now);
_baseDataSet[DicomTags.AccessionNumber].SetStringValue("ACCEEL");
_baseDataSet[DicomTags.StudyDescription].SetStringValue("X-Ray of a Moray Eel");
_baseDataSet[DicomTags.ReferringPhysiciansName].SetNullValue();
_baseDataSet[DicomTags.StudyId].SetNullValue();
//Series
_baseDataSet[DicomTags.SeriesInstanceUid].SetStringValue(DicomUid.GenerateUid().UID);
_baseDataSet[DicomTags.Modality].SetStringValue("OT");
_baseDataSet[DicomTags.SeriesNumber].SetStringValue("1");
//SC Equipment
_baseDataSet[DicomTags.ConversionType].SetStringValue("WSD");
//General Image
_baseDataSet[DicomTags.ImageType].SetStringValue(@"DERIVED\SECONDARY");
_baseDataSet[DicomTags.PatientOrientation].SetNullValue();
_baseDataSet[DicomTags.WindowWidth].SetStringValue("");
_baseDataSet[DicomTags.WindowCenter].SetStringValue("");
//Image Pixel
if (rbMonoChrome.Checked )
{
_baseDataSet[DicomTags.SamplesPerPixel].SetInt32(0, 1);
_baseDataSet[DicomTags.PhotometricInterpretation].SetStringValue("MONOCHROME2");
_baseDataSet[DicomTags.BitsAllocated].SetInt32(0, 8);
_baseDataSet[DicomTags.BitsStored].SetInt32(0, 8);
_baseDataSet[DicomTags.HighBit].SetInt32(0, 7);
_baseDataSet[DicomTags.PixelRepresentation].SetInt32(0, 0);
_baseDataSet[DicomTags.PlanarConfiguration].SetInt32(0, 0);
}
if (rbColor.Checked)
{
_baseDataSet[DicomTags.SamplesPerPixel].SetInt32(0, 3);
_baseDataSet[DicomTags.PhotometricInterpretation].SetStringValue("RGB");
_baseDataSet[DicomTags.BitsAllocated].SetInt32(0, 8);
_baseDataSet[DicomTags.BitsStored].SetInt32(0, 8);
_baseDataSet[DicomTags.HighBit].SetInt32(0, 7);
_baseDataSet[DicomTags.PixelRepresentation].SetInt32(0, 0);
_baseDataSet[DicomTags.PlanarConfiguration].SetInt32(0, 0);
}
}
private DicomFile ConvertImage(Bitmap image, int instanceNumber)
{
DicomUid sopInstanceUid = DicomUid.GenerateUid();
string fileName = @"C:\test.dcm";// String.Format("{0}.dcm", sopInstanceUid.UID);
//fileName = System.IO.Path.Combine(_tempFileDirectory, fileName);
DicomFile dicomFile = new DicomFile(fileName, new DicomAttributeCollection(), _baseDataSet.Copy());
//meta info
dicomFile.MediaStorageSopInstanceUid = sopInstanceUid.UID;
dicomFile.MediaStorageSopClassUid = SopClass.SecondaryCaptureImageStorageUid;
//General Image
dicomFile.DataSet[DicomTags.InstanceNumber].SetInt32(0, instanceNumber);
DateTime now = Platform.Time;
DateTime time = DateTime.MinValue.Add(new TimeSpan(now.Hour, now.Minute, now.Second));
//SC Image
dicomFile.DataSet[DicomTags.DateOfSecondaryCapture].SetDateTime(0, now);
dicomFile.DataSet[DicomTags.TimeOfSecondaryCapture].SetDateTime(0, time);
//Sop Common
dicomFile.DataSet[DicomTags.InstanceCreationDate].SetDateTime(0, now);
dicomFile.DataSet[DicomTags.InstanceCreationTime].SetDateTime(0, time);
dicomFile.DataSet[DicomTags.SopInstanceUid].SetStringValue(sopInstanceUid.UID);
//int rows, columns;
//Image Pixel
if (rbMonoChrome.Checked)
{
dicomFile.DataSet[DicomTags.PixelData].Values = GetMonochromePixelData(image, out rows, out columns);
}
if (rbColor.Checked)
{
dicomFile.DataSet[DicomTags.PixelData].Values = GetColorPixelData(image, out rows, out columns);
}
//Image Pixel
dicomFile.DataSet[DicomTags.Rows].SetInt32(0, rows);
dicomFile.DataSet[DicomTags.Columns].SetInt32(0, columns);
return dicomFile;
}
private static byte[] GetMonochromePixelData(Bitmap image, out int rows, out int columns)
{
rows = image.Height;
columns = image.Width;
//At least one of rows or columns must be even.
if (rows % 2 != 0 && columns % 2 != 0)
--columns; //trim the last column.
int size = rows * columns;
//byte[] pixelData = MemoryManager.Allocate<byte>(size);
byte[] pixelData = new byte[size];
int i = 0;
for (int row = 0; row < rows; ++row)
{
for (int column = 0; column < columns; column++)
{
pixelData[i++] = image.GetPixel(column, row).R;
}
}
return pixelData;
}
private static byte[] GetColorPixelData(Bitmap image, out int rows, out int columns)
{
rows = image.Height;
columns = image.Width;
//At least one of rows or columns must be even.
if (rows % 2 != 0 && columns % 2 != 0)
--columns; //trim the last column.
BitmapData data = image.LockBits(new Rectangle(0, 0, columns, rows), ImageLockMode.ReadOnly, image.PixelFormat);
IntPtr bmpData = data.Scan0;
try
{
int stride = columns * 3;
int size = rows * stride;
//byte[] pixelData = MemoryManager.Allocate<byte>(size);
byte[] pixelData = new byte[size];
for (int i = 0; i < rows; ++i)
Marshal.Copy(new IntPtr(bmpData.ToInt64() + i * data.Stride), pixelData, i * stride, stride);
//swap BGR to RGB
SwapRedBlue(pixelData);
return pixelData;
}
finally
{
image.UnlockBits(data);
}
}
private static Bitmap LoadImage(string file)
{
Bitmap image = Image.FromFile(file, true) as Bitmap;
if (image == null)
throw new ArgumentException(String.Format("The specified file cannot be loaded as a bitmap {0}.", file));
if (image.PixelFormat != PixelFormat.Format24bppRgb)
{
Platform.Log(LogLevel.Info, "Attempting to convert non RBG image to RGB ({0}) before converting to Dicom.", file);
Bitmap old = image;
using (old)
{
image = new Bitmap(old.Width, old.Height, PixelFormat.Format24bppRgb);
using (Graphics g = Graphics.FromImage(image))
{
g.DrawImage(old, 0, 0, old.Width, old.Height);
}
}
}
return image;
}
private static void SwapRedBlue(byte[] pixels)
{
for (int i = 0; i < pixels.Length; i += 3)
{
byte temp = pixels[i];
pixels[i] = pixels[i + 2];
pixels[i + 2] = temp;
}
}