Last active
February 28, 2018 01:12
-
-
Save WilliamDoman/e2365104f565a3bf9376fcec6609f432 to your computer and use it in GitHub Desktop.
Convert PDF to image and embed into dicom file
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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