Skip to content

Instantly share code, notes, and snippets.

@WilliamDoman
Last active February 28, 2018 01:12
Show Gist options
  • Save WilliamDoman/e2365104f565a3bf9376fcec6609f432 to your computer and use it in GitHub Desktop.
Save WilliamDoman/e2365104f565a3bf9376fcec6609f432 to your computer and use it in GitHub Desktop.
Convert PDF to image and embed into dicom file
using Dicom;
using Dicom.Imaging;
using Dicom.Imaging.Codec;
using Dicom.IO.Buffer;
using Ghostscript.NET;
using Ghostscript.NET.Rasterizer;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
namespace ConsoleApplication1
{
/*
"The Secondary Capture (SC) Image Information Object Definition (IOD) specifies
single-frame images that are converted from a non-DICOM format to a modality
independent DICOM format, without any constraints on pixel data format."
*/
internal class Program
{
private static void Main(string[] args)
{
GhostscriptRasterizer rasterizer = null;
GhostscriptVersionInfo version = new GhostscriptVersionInfo(
new Version(0, 0, 0), @"gsdll64.dll",
string.Empty, GhostscriptLicense.GPL);
//Path to ghostscript install
//C:\Program Files\gs\gs9.19\bin\
int dpi = 150;
var pageHeight = 1320;
var pageWidth = 1020;
var pdfContent = new MemoryStream(File.ReadAllBytes("my.pdf"));
List<Paperwork> pages = new List<Paperwork>();
using (rasterizer = new GhostscriptRasterizer())
{
rasterizer.Open(pdfContent, version, false);
//custom switches, not needed.
//rasterizer.CustomSwitches.Add("-sPAPERSIZE=letter");
//rasterizer.CustomSwitches.Add("-dPDFFitPage=true");
for (int i = 1; i <= rasterizer.PageCount; i++)
{
Image img = rasterizer.GetPage(dpi, dpi, i);
Bitmap pageImage = new Bitmap(pageWidth, pageHeight, PixelFormat.Format24bppRgb);
using (Graphics g = Graphics.FromImage(pageImage))
{
//set background color
g.Clear(Color.Black);
//g.PixelOffsetMode = PixelOffsetMode.HighQuality;
//g.CompositingQuality = CompositingQuality.HighQuality;
//g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(img, 0, 0, pageWidth, pageHeight);
BitmapInvertColors(pageImage);
pages.Add(new Paperwork(img.Size.Height, img.Size.Width, pageImage));
//500k pages
//pageImage.Save(i.ToString() + ".bmp");
}
}
rasterizer.Close();
}
//fo-dicom
DicomDataset dataset = new DicomDataset();
FillDataset(dataset);
dataset.Add(DicomTag.PhotometricInterpretation, PhotometricInterpretation.Rgb.Value);
dataset.Add(DicomTag.Rows, (ushort)pageHeight);
dataset.Add(DicomTag.Columns, (ushort)pageWidth);
DicomPixelData pixelData = DicomPixelData.Create(dataset, true);
pixelData.Height = (ushort)pageHeight;
pixelData.Width = (ushort)pageWidth;
pixelData.BitsStored = 8;
pixelData.BitsAllocated = 8;
pixelData.SamplesPerPixel = 3;
pixelData.HighBit = 7;
pixelData.PixelRepresentation = PixelRepresentation.Unsigned;
pixelData.PlanarConfiguration = PlanarConfiguration.Interleaved;
foreach (var image in pages)
{
int rows, columns;
byte[] pixels = GetPixels(image.Image, out rows, out columns);
MemoryByteBuffer buffer = new MemoryByteBuffer(pixels);
pixelData.AddFrame(buffer);
//Using a memory stream produces upside down image.
//using (var memory = new MemoryStream())
//{
// image.Image.Save(memory, ImageFormat.Bmp);
// byte[] m = memory.ToArray();
// MemoryByteBuffer buffer = new MemoryByteBuffer(m);
// pixelData.AddFrame(buffer);
//}
}
DicomFile dicomfile = new DicomFile(dataset);
DicomFile compressedFile = dicomfile.ChangeTransferSyntax(DicomTransferSyntax.JPEGProcess2_4);
compressedFile.Save("dicomfile7.dcm");
pages.ForEach(t => t.Image.Dispose());
}
private static void FillDataset(DicomDataset dataset)
{
//type 1 attributes.
dataset.Add(DicomTag.SOPClassUID, DicomUID.SecondaryCaptureImageStorage);
dataset.Add(DicomTag.StudyInstanceUID, GenerateUid());
dataset.Add(DicomTag.SeriesInstanceUID, GenerateUid());
dataset.Add(DicomTag.SOPInstanceUID, GenerateUid());
//type 2 attributes
dataset.Add(DicomTag.PatientID, "12345");
dataset.Add(DicomTag.PatientName, "dude^last");
dataset.Add(DicomTag.PatientBirthDate, "00000000");
dataset.Add(DicomTag.PatientSex, "M");
dataset.Add(DicomTag.StudyDate, DateTime.Now);
dataset.Add(DicomTag.StudyTime, DateTime.Now);
dataset.Add(DicomTag.AccessionNumber, string.Empty);
dataset.Add(DicomTag.ReferringPhysicianName, string.Empty);
dataset.Add(DicomTag.StudyID, "1");
dataset.Add(DicomTag.SeriesNumber, "1");
dataset.Add(DicomTag.ModalitiesInStudy, "CR");
dataset.Add(DicomTag.Modality, "CR");
dataset.Add(DicomTag.NumberOfStudyRelatedInstances, "1");
dataset.Add(DicomTag.NumberOfStudyRelatedSeries, "1");
dataset.Add(DicomTag.NumberOfSeriesRelatedInstances, "1");
dataset.Add(DicomTag.PatientOrientation, "F/A");
dataset.Add(DicomTag.ImageLaterality, "U");
}
private static DicomUID GenerateUid()
{
StringBuilder uid = new StringBuilder();
uid.Append("1.08.1982.10121984.2.0.07").Append('.').Append(DateTime.UtcNow.Ticks);
return new DicomUID(uid.ToString(), "SOP Instance UID", DicomUidType.SOPInstance);
}
private static byte[] GetPixels(Bitmap image, out int rows, out int columns)
{
rows = image.Height;
columns = image.Width;
if (rows % 2 != 0 && columns % 2 != 0)
--columns;
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 = 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 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;
}
}
public static void BitmapInvertColors(Bitmap bitmapImage)
{
var bitmapRead = bitmapImage.LockBits(new Rectangle(0, 0, bitmapImage.Width, bitmapImage.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppPArgb);
var bitmapLength = bitmapRead.Stride * bitmapRead.Height;
var bitmapBGRA = new byte[bitmapLength];
Marshal.Copy(bitmapRead.Scan0, bitmapBGRA, 0, bitmapLength);
bitmapImage.UnlockBits(bitmapRead);
for (int i = 0; i < bitmapLength; i += 4)
{
bitmapBGRA[i] = (byte)(255 - bitmapBGRA[i]);
bitmapBGRA[i + 1] = (byte)(255 - bitmapBGRA[i + 1]);
bitmapBGRA[i + 2] = (byte)(255 - bitmapBGRA[i + 2]);
}
var bitmapWrite = bitmapImage.LockBits(new Rectangle(0, 0, bitmapImage.Width, bitmapImage.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppPArgb);
Marshal.Copy(bitmapBGRA, 0, bitmapWrite.Scan0, bitmapLength);
bitmapImage.UnlockBits(bitmapWrite);
}
}
public class Paperwork
{
public Paperwork(int height, int width, Bitmap image)
{
this.Image = image;
this.ImageWidth = width;
this.ImageHeight = height;
}
public Bitmap Image { get; set; }
public int ImageWidth { get; set; }
public int ImageHeight { get; set; }
public string Name { get; set; }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment