Display a Simpleitk image in a picture Box - c#

I want to read a dicom or png image with simpleitk in a C# program and display the result in a pictureBox. I understand that picture Box allow only "system.drawing.image" and not itk. Is there a way to do it.
Her is my code :
OpenFileDialog fd = new OpenFileDialog();
fd.Filter = "PNG|*.png";
if (fd.ShowDialog() == DialogResult.OK)
{
string file = fd.FileName;
ImageFileReader reader = new ImageFileReader();
reader.SetFileName(file);
itk.simple.Image image = reader.Execute();
Box.Image = image;
}

You will need access to the raw image buffer which SimpleITK holds. This is accessible via the Image::GetBufferAs"TYPE" methods.
Here is a brief example on using this method:
// Cast so we know the the pixel type
input = SimpleITK.Cast(input, PixelId.sitkFloat32);
// calculate the nubmer of pixels
VectorUInt32 size = input.GetSize();
int len = 1;
for (int dim = 0; dim < input.GetDimension(); dim++) {
len *= (int)size[dim];
}
IntPtr buffer = input.GetBufferAsFloat();
I believe this can then be converted into to a Bitmap with .Net.

using (OpenFileDialog fd = new OpenFileDialog())
{
fd.Filter = "PNG|*.png";
if (fd.ShowDialog() == DialogResult.OK)
{
Box.Image = new Bitmap(fd.FileName);
}
}

Related

How to scan using NTwain

I am new to learning about scanners and tried a bunch of packages but ended up on NTwain a NuGet library. I am struggling on how to start my scanner and save the images using the api. How can I understand it? Also here's what I have so far.
Edit
I found out how to enable the scan and save it but for some reason I can't get both sides of the paper? I don't know if my encoder is wrong trying to save it as a multi-tiff or its something you have to set using NTwain.
Edit 2
I figured it out. I didn't know scanner see double sided as "Duplex" -> myDS.Capabilities.CapDuplexEnabled.SetValue(BoolType.True);
public static void GetScanner()
{
// Create appId
var appId = TWIdentity.CreateFromAssembly(DataGroups.Image, Assembly.GetExecutingAssembly());
// Attach
var session = new TwainSession(appId);
List<Image> scannedImages = new List<Image>();
session.TransferReady += (s, e) =>
{
Debug.Print("TransferReady is a go.");
};
session.DataTransferred += (s, e) =>
{
if (e.NativeData != IntPtr.Zero)
{
// Handle image data
if (e.NativeData != IntPtr.Zero)
{
var stream = e.GetNativeImageStream();
if (stream != null)
{
//Save Image to list
scannedImages.Add(Image.FromStream(stream));
}
}
}
};
// Open it
session.Open();
// Open the first source found
DataSource myDS = session.FirstOrDefault();
myDS.Open();
myDS.Capabilities.CapDuplexEnabled.SetValue(BoolType.True);
// Start Scan
myDS.Enable(SourceEnableMode.NoUI, false, IntPtr.Zero);
//Close Session
myDS.Close();
// Save Images to specific folder as tiffs
int n = 0;
foreach(Image image in scannedImages)
{
//Get the codec for tiff files
ImageCodecInfo info = null;
foreach (ImageCodecInfo ice in ImageCodecInfo.GetImageEncoders())
if (ice.MimeType == "image/tiff")
info = ice;
//Save as Multi-Page Tiff
System.Drawing.Imaging.Encoder enc = System.Drawing.Imaging.Encoder.SaveFlag;
EncoderParameters ep = new EncoderParameters(1);
ep.Param[0] = new EncoderParameter(enc, (long)EncoderValue.MultiFrame);
//Construct save path
var saveFolderPath = #"C:\Projects\SavingMethods\SavingMethods\ScannedImages\";
string fileName = "Testfile" + n + ".tiff";
var completedFilePath = Path.Combine(saveFolderPath, fileName);
//Save Image
image.Save(completedFilePath, info, ep);
n++;
}
}
I ended up figuring it out by myself but would like to thank ckuri for the comment as his link did help me immensely.
public static void GetScanner()
{
// Create appId
var appId = TWIdentity.CreateFromAssembly(DataGroups.Image,
Assembly.GetExecutingAssembly());
// Attach
var session = new TwainSession(appId);
List<Image> scannedImages = new List<Image>();
session.TransferReady += (s, e) =>
{
Debug.Print("TransferReady is a go.");
};
session.DataTransferred += (s, e) =>
{
if (e.NativeData != IntPtr.Zero)
{
// Handle image data
if (e.NativeData != IntPtr.Zero)
{
var stream = e.GetNativeImageStream();
if (stream != null)
{
//Save Image to list
scannedImages.Add(Image.FromStream(stream));
}
}
}
};
// Open it
session.Open();
// Open the first source found
DataSource myDS = session.FirstOrDefault();
myDS.Open();
myDS.Capabilities.CapDuplexEnabled.SetValue(BoolType.True);
// Start Scan
myDS.Enable(SourceEnableMode.NoUI, false, IntPtr.Zero);
//Close Session
myDS.Close();
// Save Images to specific folder as tiffs
int n = 0;
foreach(Image image in scannedImages)
{
//Get the codec for tiff files
ImageCodecInfo info = null;
foreach (ImageCodecInfo ice in ImageCodecInfo.GetImageEncoders())
if (ice.MimeType == "image/tiff")
info = ice;
//Save as Multi-Page Tiff
System.Drawing.Imaging.Encoder enc = System.Drawing.Imaging.Encoder.SaveFlag;
EncoderParameters ep = new EncoderParameters(1);
ep.Param[0] = new EncoderParameter(enc, (long)EncoderValue.MultiFrame);
//Construct save path
var saveFolderPath = #"C:\Projects\SavingMethods\SavingMethods\ScannedImages\";
string fileName = "Testfile" + n + ".tiff";
var completedFilePath = Path.Combine(saveFolderPath, fileName);
//Save Image
image.Save(completedFilePath, info, ep);
n++;
}
}

C# Save Image files using SaveFileDialog or FolderBrowserDialog

I'm trying to save image files which are converted from PDF to PNG. I want my application to save the converted image if the PDF was a single page document using the "SaveFileDialog", and if the PDF file was a multi-page document, I then want my application to save them into a folder using the "FolderBrowserDialog".
My problem is that if the PDF file was a multi-page document, my code would first save the first image (after conversion) using the "SaveFileDialog" before attempting to save the rest of the images using "FolderBrowserDialog".
Here is what I've tried.
Image = imageToConvert = null;
for (int i = 0; i < images.Length; i++)
{
if (i == 0)
{
//Save converted image if PDF is single page
imageToConvert = images[i];
SaveFileDialog _saveFile = new SaveFileDialog();
_saveFile.Title = "Save file";
_saveFile.Filter = "PNG|*.png";
_saveFile.FileName = Lbl_OriginalFileName.Text;
if (_saveFile.ShowDialog() == DialogResult.OK)
{
imageToConvert.Save(_saveFile.FileName, ImageFormat.Png);
imageToConvert.Dispose();
}
else if (_saveFile.ShowDialog() == DialogResult.Cancel)
{
return;
}
}
else
{
if (i > 0)
{
// Save converted Images if PDF is multi-page
Image imageToConvert2 = images[i];
FolderBrowserDialog fbd = new FolderBrowserDialog();
fbd.ShowDialog();
fbd.Description = "Select the folder you want save your files into.";
string pathString = Path.Combine(fbd.SelectedPath, subFolder);
Directory.CreateDirectory(pathString);
if (fbd.ShowDialog() == DialogResult.Cancel)
{
return;
}
string saveFileNamesPNG = string.Format(Lbl_OriginalFileName.Text + "_" + i.ToString() + ".png", ImageFormat.Png);
imageToConvert.Save(Path.Combine(pathString, saveFileNamesPNG));
imageToConvert.Dispose();
}
}
}
I would really appreciate any help.
I moved the test outside the loop and then checked if it is one page and use the SaveFileDialog. And if there are more than one, I then used a FolderBrowserDialog with the For-loop to save the images.

The value was either too small or too large for an unsigned byte C#

I have 2 methods, shown below, and i can't get it to work. I am trying to open a .png file from a OpenFileDialog and display it on a ImageBox:
public static Bitmap ToBitmap(this string input)
{
List<byte> splitBytes = new List<byte>();
string byteString = "";
foreach (char i in input)
{
byteString += i;
if (byteString.Length == 3)
{
splitBytes.Add(Convert.ToByte(byteString));
byteString = "";
}
}
if (byteString != "")
splitBytes.AddRange(Encoding.ASCII.GetBytes(byteString));
using (var ms = new MemoryStream(splitBytes.ToArray()))
{
var img = Image.FromStream(ms);
Bitmap output = new Bitmap(img);
return output;
}
}
public static string StringFromFile(string input)
{
StreamReader sr = new StreamReader(input);
string file = string.Empty;
while (sr.EndOfStream == false)
{
file += sr.Read();
}
return file;
}
In another file i tried to use the method:
OpenFileDialog OFD = new OpenFileDialog();
OFD.Filter = "Images (*.png)|*.png";
OFD.ShowDialog();
pictureBox1.BackgroundImageLayout = ImageLayout.Stretch;
pictureBox1.BackgroundImage = StringToBitmapConverter.ToBitmap(StringToBitmapConverter.StringFromFile(OFD.FileName));
But I get this exception:
System.OverflowException: 'Value was either too large or too small for an unsigned byte.'
Please help!
I am using these methods in a class called StringToBitmapConverter, and there is an error that is giving me trouble, can anyone help me?
So according to the documentation Convert.ToByte(string value):
Converts the specified string representation of a number to an equivalent 8-bit unsigned integer.
And the method will throw an OverflowException if:
value represents a number that is less than Byte.MinValue or greater than Byte.MaxValue.
So the value of byteString must be less than 0 or greater than 255 at this line:
splitBytes.Add(Convert.ToByte(byteString));
You could use try { } catch to catch the error or use byte.TryParse to only convert those numbers that are actually convertable.
Reading text from a File can be done by File.ReadAllText
Your algorythm splits the read text into characterblocks of 3 and interprets the text as byte:
"23405716119228936" -> 234,57,161,192,289,36 .... 289 does notfit into a byte -> exception. Check the files content.
if (byte.TryParse(byteString, out var b))
{
splitBytes.Add(b);
}
else
{
// this thing is not convertable to byte, do something with it....
}
Edit#1:
I guess reading in PNG-Files as "string" and converting them as you do does not work.
PNG Files have an internal format, they are encoded. See
https://www.w3.org/TR/PNG/
or
https://de.wikipedia.org/wiki/Portable_Network_Graphics
They are not strings that you can simply group into 3 chars, convert to byte and reinterprete as memory string.
For giggles try this on your file to see what is your input.:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
internal class Program
{
static void Main(string[] args)
{
foreach (var s in Make3CharChunks(File.ReadAllText( /*your file path here*/ ""))
Console.WriteLine(s);
Console.ReadLine();
}
static IEnumerable<string> Make3CharChunks(string s)
=> s.Aggregate(new List<string>(), (acc, c) =>
{
if (acc.Any() && acc.Last().Count() < 3)
acc[acc.Count - 1] = $"{acc.Last()}{c}";
else
acc.Add(c.ToString());
return acc;
});
}
If all you are doing is trying to open a png you can throw away most all of your code and simplify it to
OpenFileDialog OFD = new OpenFileDialog();
OFD.Filter = "Images (*.png)|*.png";
var result = OFD.ShowDialog()
if(result == DialogResult.OK) //You need to check to see if they clicked OK or Cancel.
{
pictureBox1.BackgroundImageLayout = ImageLayout.Stretch;
var oldImage = pictureBox1.BackgroundImage
pictureBox1.Image = new Bitmap(OFD.FileName); //Shouold be Image, not BackgroundImage for a picture box.
if(oldImage != null)
{
oldImage.Dispose();
}
}

How to convert a view into a PNG?

I want to create a PNG from a view. I am using this code:
//I instance the user control
ucFormToPrintView miViewToPrint = new ucFormToPrintView();
miViewToPrint.DataContext = ((ucFormToPrintView)CCForm).DataContext;
//I use a RenderTargetBitmap to render the user control
System.Windows.Media.Imaging.RenderTargetBitmap rtb = new System.Windows.Media.Imaging.RenderTargetBitmap(794, 1122, 72, 72, System.Windows.Media.PixelFormats.Pbgra32);
rtb.Render(miViewToPrint);
//I use an encoder to create the png
System.Windows.Media.Imaging.PngBitmapEncoder encoder = new System.Windows.Media.Imaging.PngBitmapEncoder();
encoder.Frames.Add(System.Windows.Media.Imaging.BitmapFrame.Create(rtb));
//I use a dialog to select the path where to save the png file
Microsoft.Win32.SaveFileDialog saveFileDialog = new Microsoft.Win32.SaveFileDialog();
saveFileDialog.FilterIndex = 1;
if (saveFileDialog.ShowDialog() == true)
{
using (System.IO.Stream stream = saveFileDialog.OpenFile())
{
encoder.Save(stream);
stream.Close();
System.Diagnostics.Process.Start(saveFileDialog.FileName);
}
}
The result is an empty png.
How can I create a png file from a user control?
Thank so much.
The UserControl has to be laid out at least once to be visible. You can achieve that by calling its Measure and Arrange methods.
var miViewToPrint = new ucFormToPrintView();
miViewToPrint.DataContext = ((ucFormToPrintView)CCForm).DataContext;
// layout, i.e. measure and arrange
miViewToPrint.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
miViewToPrint.Arrange(new Rect(miViewToPrint.DesiredSize));
...
if (saveFileDialog.ShowDialog() == true)
{
using (var stream = saveFileDialog.OpenFile())
{
encoder.Save(stream);
}
System.Diagnostics.Process.Start(saveFileDialog.FileName);
}

Save images from listview to a folder

I had this listview and a button. There are also several images inside the listview. I want to save the images from the listview inside the folder when the button is pressed. And I don't know how to do it. Could you please help me out? Thanks. This is the code I use to insert images to the listview.
OpenFileDialog opend1 = new OpenFileDialog();
opend1.Filter = "Image Files(*.BMP;*.JPG;*.GIF)|*.BMP;*.JPG;*.GIF|All files (*.*)|*.*";
opend1.Multiselect = true;
if (opend1.ShowDialog() == DialogResult.OK)
{
listView1.View = View.LargeIcon;
imageList.ImageSize = new Size(100, 100);
for (int c = 0; c < opend1.FileNames.Length; c++)
{
Image i = Image.FromFile(opend1.FileNames[c].ToString());
Image img = i.GetThumbnailImage(100, 100, null, new IntPtr());
imageList.Images.Add(img);
}
listView1.LargeImageList = imageList;
ListViewItem lstItem = new ListViewItem();
lstItem.ImageIndex = imageList.Images.Count-1;
listView1.Items.Add(lstItem);
listView1.Refresh();
}
For each image in your image list (imageList.Images) call this (with your own supplied directory and file name):
img.Save(#"C:\MyImage.jpg", ImageFormat.Jpeg);
foreach (Image image in listView1.LargeImageList.Images)
{
string filename = ""; // make this whatever you need...
image.Save(filename);
}

Categories