For school we have to do a project in stenography, I have chosen to use a bmp and put text into it. It works fine with normal pictures but from the moment on when you have pictures with a same byte sequence for example a white area or the image where I had the problem is this picture.
When I make from the bytearray where the text is in an image and I read it back the bytearray has changed. while the only thing I did was making an image from the bytearray and from the image back a bytearray.
This is my code:
namespace steganografie
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void btnFile_Click(object sender, EventArgs e)
{
OpenFileDialog dialog = new OpenFileDialog();
dialog.Filter = "bmp files (*.bmp)|*.bmp|All files (*.*)|*.*";
dialog.Title = "Select a image";
dialog.InitialDirectory = Application.ExecutablePath;
if (dialog.ShowDialog() == DialogResult.OK)
{
txtText.Enabled = true;
txtFile.Text = dialog.FileName;
byte[] arImage = imageToByteArray(Image.FromFile(txtFile.Text));
txtText.MaxLength = ((arImage.Length -54) /8)-5;
lblCharLeft.Text = txtText.MaxLength+"";
lblCharLeft.Tag = txtText.MaxLength;
picOriginal.Image = Image.FromFile(dialog.FileName);
}
}
private void btnSteganografie_Click(object sender, EventArgs e)
{
byte[] arImage = imageToByteArray(Image.FromFile(txtFile.Text));
string input = txtText.Text;
string inputInBits = GetBits(input);
char[] bits = inputInBits.ToCharArray();
int i = 0;
for (i = 54; (i < arImage.Length & i < bits.Length+54); i++)
{
if ((int)arImage[i] == 0)
{
arImage[i] = (byte)2;
}
if ((int)arImage[i] == 255)
{
byte bBit = new byte();
bBit = 2;
arImage[i] = (byte)(arImage[i]-bBit);
}
int lastBit = ((int)arImage[i]) % 2;
int dataBit = ((int)bits[i - 54])%2;
if (lastBit != dataBit)
{
arImage[i]++;
}
}
arImage[i] = 0;
Image result = byteArrayToImage(arImage);
picEncoded.Image = result;
SaveFileDialog sfd = new SaveFileDialog();
if (sfd.ShowDialog() == DialogResult.OK)
{
result.Save(sfd.FileName+".bmp",System.Drawing.Imaging.ImageFormat.Bmp);
}
}
public string GetBits(string input)
{
StringBuilder sbBuilder = new StringBuilder();
byte[] bytes = Encoding.Unicode.GetBytes(input);
foreach (byte bByte in Encoding.Unicode.GetBytes(input))
{
int iByte = (int)bByte;
for (int i = 7; i >= 0 & (iByte!=0 | i!=7); i--)
{
if (iByte - Math.Pow(2, i) >= 0)
{
sbBuilder.Append("1");
iByte -= (int)Math.Pow(2, i);
}
else
{
sbBuilder.Append("0");
}
}
}
return sbBuilder.ToString();
}
public byte[] imageToByteArray(System.Drawing.Image imageIn)
{
MemoryStream ms = new MemoryStream();
imageIn.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
return ms.ToArray();
}
public Image byteArrayToImage(byte[] byteArrayIn)
{
//**********ERROR HAPPENS HERE *************
MemoryStream ms = new MemoryStream(byteArrayIn);
Image returnImage = Image.FromStream(ms);
byte[] arImageTEST = imageToByteArray(returnImage);
//**********byteArrayIn should be the same as arImageTEST ***********
return returnImage;
}
}
Maybe it has something to do with this information available here:
You must keep the stream open for the
lifetime of the Image.
Hope it helps.
Related
I'm trying to capture a bitmap from desktop and then stream that to another device on the local network via socket connection.
I have a working example of this using gdi that sends a bitmap via socket to the client device and renders it to a picture box, but this solution is pretty inefficient as I'm sending unchanged bitmaps and it requires a lot of cpu processing on the client.
I'll include this example as a reference point
public class Serial
public static byte[] BitmapToBytes(Bitmap bitmap) {
using(MemoryStream ms = new MemoryStream()) {
using(BinaryWriter bw = new BinaryWriter(ms)) {
using(MemoryStream msb = new MemoryStream()) {
bitmap.Save(msb, ImageFormat.Jpeg);
byte[] bitmapBytes = msb.ToArray();
bw.Write(bitmapBytes.Length);
bw.Write(bitmapBytes);
return ms.ToArray();
}
}
}
}
public static Bitmap BytesToBitmap(byte[] bytes) {
using(MemoryStream ms = new MemoryStream(bytes)) {
using(BinaryReader br = new BinaryReader(ms)) {
int len = br.ReadInt32();
byte[] bitmapBytes = br.ReadBytes(len);
if(len == bitmapBytes.Length) {
using(MemoryStream msb = new MemoryStream(bitmapBytes)) {
return new Bitmap(msb);
}
} else {
return null;
}
}
}
}
}
public class Send {
private ClientInfo Instance;
public Send(ClientInfo instance) {
Instance = instance;
}
public void Bitmap(Bitmap bitmap) {
if(!Instanced) { return; }
Instance.SendMessage((uint)Code.Bitmap, Serial.BitmapToBytes(bitmap));
}
}
public class Server { //Same code for Client
public event EventHandler<BitmapEventArgs> BitmapReceived = delegate { };
//Socket connection setup code stripped as it's not relevant
private void Data_Received(ClientInfo c, uint code, byte[] bytes, int len) {
switch((Code)code) {
case Code.BitmapReceived:
BitmapReceived(this, new BitmapEventArgs(Serial.BytesToBitmap(bytes)));
break;
}
}
}
public partial class Form1 : Form {
private Client Client;
private Server Server;
private Send Send;
private void StartSocket() {
new Thread(() => {
StopSocket();
Client = new Client();
Client.ClientConnected += Client_Connected;
Client.ClientDisconnected += Client_Disconnected;
Client.BitmapReceived += Bitmap_Received;
if(!Client.Start(Config.Connection.IP, Config.Connection.Port)) {
Client = null;
Server = new Server();
Server.ClientConnected += Client_Connected;
Server.ClientDisconnected += Client_Disconnected;
Server.BitmapReceived += Bitmap_Received;
Server.Start(Config.Connection.Port);
}
}).Start();
}
private void Client_Connected(object sender, EventArgs e) {
if(sender is Server) {
Send = new Send(Server.Instance);
} else {
Send = new Send(Client.Instance);
}
}
private void SendBitmap() {
if(Send == null) { return; }
new Thread(() => {
while(Send != null) {
Bitmap b = CaptureBitmap();
if(b != null) {
Send.Bitmap(b);
Thread.Sleep(16); //around 60 times a second
}
}
}).Start();
}
private void Bitmap_Received(object sender, BitmapEventArgs e) {
if(Send != null && e.Bitmap != null) {
BitmapPicBox.Image = e.Bitmap;
}
}
private Bitmap CaptureBitmap() {
IntPtr deskHandle = WinApi.GetDesktopWindow();
IntPtr dc = WinApi.GetWindowDC(deskHandle);
if(dc != IntPtr.Zero) {
if(WinApi.GetWindowRect(deskHandle, out WinApi.RECT winRect)) {
IntPtr hdcDest = WinApi.CreateCompatibleDC(dc);
IntPtr hBitmap = WinApi.CreateCompatibleBitmap(dc, winRect.Width, winRect.Height);
IntPtr hOld = WinApi.SelectObject(hdcDest, hBitmap);
if(WinApi.BitBlt(hdcDest, 0, 0, winRect.Width, winRect.Height, dc, winRect.Left, winRect.Top, WinApi.TernaryRasterOperations.SRCCOPY)) {
WinApi.SelectObject(hdcDest, hOld);
WinApi.DeleteDC(hdcDest);
WinApi.ReleaseDC(deskHandle, dc);
Bitmap b = Image.FromHbitmap(hBitmap);
WinApi.DeleteObject(hBitmap);
return b;
} else {
WinApi.DeleteDC(hdcDest);
WinApi.ReleaseDC(deskHandle, dc);
WinApi.DeleteObject(hBitmap);
}
}
}
return null;
}
}
I have since tried a SharpDX implementation. I used the example from this github project for getting desktop image by desktop duplication and feeding that to a panel on the form which renders it.
But I'm not sure how I'd integrate this into my socket connection, I'd need to pass the frame being created as a byte array, and then back into a Bitmap1 that can be rendered.
Receiving the byte array and converting to Bitmap1 would be here:
private void RenderDuplicatedFrame(byte[] bitmapBytes) {
//Convert bitmapBytes to SharpDX.Direct2D1.Bitmap1
SharpDX.Direct2D1.Bitmap1 bitmap = //???
_backBufferDc.Value.BeginDraw();
_backBufferDc.Value.Clear(new RawColor4(0, 0, 0, 1));
using(bitmap) {
var renderX = (Size.Width - RenderSize.Width) / 2;
var renderY = (Size.Height - RenderSize.Height) / 2;
_backBufferDc.Value.DrawBitmap(bitmap, new RawRectangleF(renderX, renderY, renderX + RenderSize.Width, renderY + RenderSize.Height), 1, BitmapInterpolationMode.Linear);
}
_backBufferDc.Value.EndDraw();
_swapChain.Value.Present(1, 0);
}
Sending the Bitmap1 would be here:
private void AcquireFrame() {
var od = _outputDuplication.Value;
SharpDX.DXGI.Resource frame;
OutputDuplicateFrameInformation frameInfo;
od.AcquireNextFrame(500, out frameInfo, out frame);
using(frame) {
if(frameInfo.LastPresentTime != 0) {
using(var frameSurface = frame.QueryInterface<Surface>()) {
using(var frameDc = new SharpDX.Direct2D1.DeviceContext(_2D1Device.Value, DeviceContextOptions.EnableMultithreadedOptimizations)) {
using(var frameBitmap = new Bitmap1(frameDc, frameSurface)) {
//Convert frameBitmap to byte array here to send over socket
}
}
}
}
od.ReleaseFrame();
}
}
So how do I go about converting to and from a byte array?
I am a starting student in C# and I can't find the answer for the following question:
"Write a program to open a text file and save the individual high and low 4 bit nibbles of each byte and in a binary file. Write a program to do the reerse, i.e reads two bytes from a binary file, combines them and writes them as a text file."
I can read code, and understand it. But since i'm new to this field, it's hard for me to actually come up on it completely on my own.
I've already wrote the code to open a .txt file and to save it as an .txt file.
Image of form1: Since I lack the "reputation" I can't post images. :(
And this is the code I wrote:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
namespace _9._3_menustripAndFiledialog
{
public partial class Form1 : Form
{
private System.Drawing.Printing.PrintDocument docToPrint =
new System.Drawing.Printing.PrintDocument();
public Form1()
{
InitializeComponent();
}
private void helpToolStripMenuItem_Click(object sender, EventArgs e)
{
}
private void openToolStripMenuItem_Click(object sender, EventArgs e)
{
//Clear rich text box
richTextBox1.Clear();
//Set open file dialog initial directory and title
openFileDialog1.InitialDirectory = #"C:\"; //Hier zeg je welke directory drive hij moet openen
openFileDialog1.Title = "Please select a file";
openFileDialog1.Filter= "Text files(*.TXT)|*.txt";
MessageBox.Show("Only .txt files can be opened.");
//Open the dialog and check for cancel
if (openFileDialog1.ShowDialog() != DialogResult.Cancel)
{
// niet gecanceled - lees bestand
richTextBox1.LoadFile(openFileDialog1.FileName, RichTextBoxStreamType.PlainText);
}
else
{
MessageBox.Show("Gosh darn it! You pressed cancel!");
}
}
private void saveToolStripMenuItem_Click(object sender, EventArgs e)
{
if(saveFileDialog1.ShowDialog() != DialogResult.Cancel)
{
// niet gecanceld - schrijf het bestand
richTextBox1.SaveFile(saveFileDialog1.FileName, RichTextBoxStreamType.PlainText);
} else {
MessageBox.Show("You pressed cancel!");
}
}
private void exitToolStripMenuItem_Click(object sender, EventArgs e)
{
// Display a message box asking users if they
// want to exit the application.
if (MessageBox.Show("Do you want to exit?", "My Application",
MessageBoxButtons.YesNo, MessageBoxIcon.Question)
== DialogResult.Yes)
{
Application.Exit();
}
}
private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
{
AboutBox1 frmAbout = new AboutBox1();
frmAbout.Show();
}
private void cutToolStripMenuItem_Click(object sender, EventArgs e)
{
richTextBox1.Cut();
}
private void pasteToolStripMenuItem_Click(object sender, EventArgs e)
{
richTextBox1.Paste();
}
private void undoToolStripMenuItem_Click(object sender, EventArgs e)
{
richTextBox1.Undo();
}
private void copyToolStripMenuItem_Click(object sender, EventArgs e)
{
richTextBox1.Copy();
}
private void redoToolStripMenuItem_Click(object sender, EventArgs e)
{
richTextBox1.Redo();
}
private void findTextToolStripMenuItem_Click(object sender, EventArgs e)
{
richTextBox1.Find("Text", RichTextBoxFinds.MatchCase);
richTextBox1.SelectionFont = new Font("Verdana", 12, FontStyle.Italic);
richTextBox1.SelectionColor = Color.Blue;
}
public void replaceTextToolStripMenuItem_Click(object sender, EventArgs e)
{
richTextBox1.Text = richTextBox1.Text.Replace("Text", "newText");
}
private void printToolStripMenuItem_Click(object sender, EventArgs e)
{
printDialog1.AllowSomePages = true;
printDialog1.ShowHelp = true;
printDialog1.Document = docToPrint;
DialogResult result = printDialog1.ShowDialog();
if (result == DialogResult.OK)
{
docToPrint.Print();
}
}
//Code starting from here are added from user: Xanatos
public static void ReadSplitWrite(string inputFile, string outputFile)
{
using (var sr = File.OpenRead(inputFile))
using (var sw = File.Create(outputFile))
{
int read;
byte[] inputBuffer = new byte[4096];
byte[] outputBuffer = new byte[inputBuffer.Length * 2];
while ((read = sr.Read(inputBuffer, 0, inputBuffer.Length)) != 0)
{
for (int i = 0, j = 0; i < read; i++, j += 2)
{
outputBuffer[j] = (byte)(inputBuffer[i] & 0x0F);
outputBuffer[j + 1] = (byte)(inputBuffer[i] & 0xF0);
}
sw.Write(outputBuffer, 0, read * 2);
}
}
}
public static void ReadMergeWrite(string inputFile, string outputFile)
{
using (var sr = File.OpenRead(inputFile))
using (var sw = File.Create(outputFile))
{
int read;
byte[] inputBuffer = new byte[4096 * 2];
byte[] outputBuffer = new byte[inputBuffer.Length / 2];
while ((read = sr.Read(inputBuffer, 0, inputBuffer.Length)) != 0)
{
for (int i = 0, j = 0; i < read; i += 2, j++)
{
outputBuffer[j] = inputBuffer[i];
outputBuffer[j] |= inputBuffer[i + 1];
}
sw.Write(outputBuffer, 0, read / 2);
}
}
}
//I made a custom button to support the read and write method and to have it inside my form
private void openAndSaveAsBinaryToolStripMenuItem_Click(object sender, EventArgs e)
{
ReadSplitWrite("inputfile.txt", "output.dat");
ReadMergeWrite("output.dat", "inputfile2.txt");
}
}
}
I would really appreciate some help on this matter! :)
Thanks in advance!
I tried something and this is what I came up with as sollution to the question.
private void openAndSaveAsBinaryToolStripMenuItem_Click(object sender, EventArgs e)
{
string dirPath = #"C:\";
//read from folder: C:\
//create directory if it doesn't exist
if (!Directory.Exists(dirPath))
{
Directory.CreateDirectory(dirPath);
}
string fileName = #dirPath + "/TestFile.bin";
//Create binary file if it doesn't exist
if (!File.Exists(fileName))
{
//File doesn't exist - create file
FileStream fs = new FileStream(fileName, FileMode.CreateNew);
BinaryWriter bw = new BinaryWriter(fs);
byte[] byteArray = { 0x48, 0x45, 0x4C, 0x4C, 0x4F }; //HELLO!
for (int i = 0; i < byteArray.Length; i++)
{
bw.Write(byteArray[i]);
}
bw.Close();
fs.Close();
}
// reads back
FileStream fsRead = new FileStream(fileName, FileMode.Open);
BinaryReader br = new BinaryReader(fsRead);
for (int i = 0; i < fsRead.Length; i++)
{
MessageBox.Show(br.ReadByte().ToString());
}
br.Close();
fsRead.Close();
}
What it does: It creates a new directory if it doesn't exists. Also, it writes the .bin file now and returns it to me in a MessageBox as Binary. (Converted .ToString()). After that it saved it in the directory,and it converts it in the .bin to readable text.
I think this is what the assignment asked from me.
I want to thank you folks for the help, without it I couldn't have done it :)
Here there are two methods, the first one splits, the second one merges. Note that your assignment isn't clear if you have to shift the second nibble after splitting it or not... To make it clear:
0xFF
should I split it to:
0x0F 0xF0
or to
0x0F 0x0F
I choose the first one.
public static void ReadSplitWrite(string inputFile, string outputFile)
{
using (var sr = File.OpenRead(inputFile))
using (var sw = File.Create(outputFile))
{
int read;
byte[] inputBuffer = new byte[4096];
byte[] outputBuffer = new byte[inputBuffer.Length * 2];
while ((read = sr.Read(inputBuffer, 0, inputBuffer.Length)) != 0)
{
for (int i = 0, j = 0; i < read; i++, j += 2)
{
outputBuffer[j] = (byte)(inputBuffer[i] & 0x0F);
outputBuffer[j + 1] = (byte)(inputBuffer[i] & 0xF0);
}
sw.Write(outputBuffer, 0, read * 2);
}
}
}
public static void ReadMergeWrite(string inputFile, string outputFile)
{
using (var sr = File.OpenRead(inputFile))
using (var sw = File.Create(outputFile))
{
int read;
byte[] inputBuffer = new byte[4096 * 2];
byte[] outputBuffer = new byte[inputBuffer.Length / 2];
while ((read = sr.Read(inputBuffer, 0, inputBuffer.Length)) != 0)
{
for (int i = 0, j = 0; i < read; i += 2, j++)
{
outputBuffer[j] = inputBuffer[i];
outputBuffer[j] |= inputBuffer[i + 1];
}
sw.Write(outputBuffer, 0, read / 2);
}
}
}
Use it like:
ReadSplitWrite("inputfile.txt", "output.dat");
ReadMergeWrite("output.dat", "inputfile2.txt");
If you look at the example, you will see that I read the file at blocks of 4096/8192 bytes at a time (inputBuffer), and then I have a second buffer where I put the splitted/merged bytes that I then write.
My utility is supposed to resize either .jpg or .png files.
It seems to work fine in one location (at work, where I don't have IrfanView installed). But at home, when I open a *.jpg and then save it (resized), I see:
However, the image still displays fine in either case (whether I select "Yes" or "No" in the dialog.
IOW, I'm able to load and save both jpgs and pngs, and they save as such, and display fine. But IrfanView claims they are messed up.
Actually, I'm not sure how the image is saved; I was assuming it just saved it in the proper format "behind the scenes" based on the extension. Anyway, as this is a rather simple utility, I will just show all the code:
using System;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
namespace FileResizingUtil
{
public partial class FormFileResizer : Form
{
private Image _imgToResize;
String _originalFilename = String.Empty;
public FormFileResizer()
{
InitializeComponent();
}
private void buttonChooseImage_Click(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog
{
InitialDirectory = "c:\\",
Filter = "JPG files (*.jpg)|*.jpg| PNG files (*.png)|*.png", FilterIndex = 2, RestoreDirectory = true
};
if (ofd.ShowDialog() == DialogResult.OK)
{
try
{
_originalFilename = ofd.FileName;
_imgToResize = Image.FromFile(_originalFilename);
}
catch (Exception ex)
{
MessageBox.Show("Error: Could not read file from disk. Original error: " + ex.Message);
}
}
// If made it to here, it must be good
String preamble = labelImgSelected.Text;
labelImgSelected.Text = String.Format("{0}{1}", preamble, _originalFilename);
textBoxOrigHeight.Text = _imgToResize.Height.ToString();
textBoxOrigWidth.Text = _imgToResize.Width.ToString();
buttonApplyPercentageChange.Enabled = true;
//buttonResizeImage.Enabled = true;
}
private void buttonResizeImage_Click(object sender, EventArgs e)
{
// Really large images take awhile, so show an hourglass
Cursor.Current = Cursors.WaitCursor;
try
{
var size = new Size { Height = Convert.ToInt32(textBoxNewHeight.Text), Width = int.Parse(textBoxNewWidth.Text) };
// Two different ways of getting the int val
Image resizedImg = FileResizeUtils.GetResizedImage(_imgToResize, size);
String fileNameSansExtension = Path.GetFileNameWithoutExtension(_originalFilename);
String fileNameExtension = Path.GetExtension(_originalFilename);
String newFilename = String.Format("{0}{1}_{2}{3}", fileNameSansExtension, size.Height, size.Width, fileNameExtension);
// If used a different extension (jpg where the original was png, or vice versa) would the Save be intelligent enough to actually save in the other format?
resizedImg.Save(newFilename);
MessageBox.Show(String.Format("Done! File saved as {0}", newFilename));
Recycle();
}
finally
{
Cursor.Current = Cursors.Default;
}
}
private void Recycle()
{
buttonResizeImage.Enabled = false;
buttonApplyPercentageChange.Enabled = false;
labelImgSelected.Text = "Image selected: ";
textBoxOrigHeight.Text = String.Empty;
textBoxOrigWidth.Text = String.Empty;
// Retain the percentage vals, as it may be that all in a batch need to be the same pair of vals
}
private void buttonApplyPercentageChange_Click(object sender, EventArgs e)
{
int origHeight = _imgToResize.Height;
int origWidth = _imgToResize.Width;
// Two ways to convert the val
double heightFactor = (double)numericUpDownHeight.Value / 100.0;
double widthFactor = Convert.ToDouble(numericUpDownWidth.Value) / 100.0;
if (heightFactor < 0 || widthFactor < 0)
{
// show an error - no negative values allowed- using updown, so that should not be possible
}
var newHeight = Convert.ToInt32(origHeight * heightFactor);
var newWidth = Convert.ToInt32(origWidth * widthFactor);
textBoxNewHeight.Text = newHeight.ToString();
textBoxNewWidth.Text = newWidth.ToString();
buttonResizeImage.Enabled = true;
}
private void textBoxNewHeight_TextChanged(object sender, EventArgs e)
{
EnableResizeButtonIfValidDimensionsEntered();
}
private void EnableResizeButtonIfValidDimensionsEntered()
{
if (String.IsNullOrWhiteSpace(textBoxOrigHeight.Text)) return;
String candidateHeight = textBoxNewHeight.Text;
String candidateWidth = textBoxNewWidth.Text;
int validHeight;
int validWidth;
buttonResizeImage.Enabled = (int.TryParse(candidateHeight, out validHeight)) &&
(int.TryParse(candidateWidth, out validWidth));
}
private void numericUpDownHeight_ValueChanged(object sender, EventArgs e)
{
if (checkBoxRetainRatio.Checked)
{
numericUpDownWidth.Value = numericUpDownHeight.Value;
}
}
private void numericUpDownWidth_ValueChanged(object sender, EventArgs e)
{
if (checkBoxRetainRatio.Checked)
{
numericUpDownHeight.Value = numericUpDownWidth.Value;
}
}
}
}
..and the GUI (just prior to hitting the "Resize Image" button:
UPDATE
Based on Eugene Sh.'ls comment, I changed my Save method to the following block:
bool success = true;
. . .
if (fileNameExtension != null && fileNameExtension.ToLower().Contains("jpg"))
{
resizedImg.Save(newFilename, ImageFormat.Jpeg);
}
else if (fileNameExtension != null &&
fileNameExtension.ToLower().Contains("png"))
{
resizedImg.Save(newFilename, ImageFormat.Png);
}
else
{
success = false;
}
if (success)
{
MessageBox.Show(String.Format("Done! File saved as {0}", newFilename));
}
else
{
MessageBox.Show("Something went awry. The file was not saved");
}
UPDATE 2
So here is my new code, implementing the suggestion, and supporting several new file types:
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Windows.Forms;
namespace FileResizingUtil
{
public partial class FormFileResizer : Form
{
private Image _imgToResize;
String _originalFilename = String.Empty;
public FormFileResizer()
{
InitializeComponent();
}
private void buttonChooseImage_Click(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog
{
InitialDirectory = "c:\\",
Filter = "JPG files (*.jpg)|*.jpg| PNG files (*.png)|*.png| BMP files (*.bmp)|*.bmp| TIFF files (*.tiff)|*.png| ICO files (*.ico)|*.ico| EMF files (*.emf)|*.emf| WMF files (*.wmf)|*.wmf",
FilterIndex = 1, RestoreDirectory = true
};
if (ofd.ShowDialog() == DialogResult.OK)
{
try
{
_originalFilename = ofd.FileName;
_imgToResize = Image.FromFile(_originalFilename);
}
catch (Exception ex)
{
MessageBox.Show("Error: Could not read file from disk. Original error: " + ex.Message);
}
}
if (String.IsNullOrWhiteSpace(_originalFilename)) return;
// If made it to here, it must be good
String preamble = labelImgSelected.Text;
labelImgSelected.Text = String.Format("{0}{1}", preamble, _originalFilename);
textBoxOrigHeight.Text = _imgToResize.Height.ToString();
textBoxOrigWidth.Text = _imgToResize.Width.ToString();
buttonApplyPercentageChange.Enabled = true;
}
private void buttonResizeImage_Click(object sender, EventArgs e)
{
bool success = true;
// Really large images take awhile, so show an hourglass
Cursor.Current = Cursors.WaitCursor;
try
{
// Two different ways of getting the int val
var size = new Size { Height = Convert.ToInt32(textBoxNewHeight.Text), Width = int.Parse(textBoxNewWidth.Text) };
Image resizedImg = FileResizeUtils.GetResizedImage(_imgToResize, size);
String fileNameSansExtension = Path.GetFileNameWithoutExtension(_originalFilename);
String fileNameExtension = Path.GetExtension(_originalFilename);
String newFilename = String.Format("{0}{1}_{2}{3}", fileNameSansExtension, size.Height, size.Width, fileNameExtension);
if (fileNameExtension != null && fileNameExtension.ToLower().Contains("jpg"))
{
resizedImg.Save(newFilename, ImageFormat.Jpeg);
}
else if (fileNameExtension != null && fileNameExtension.ToLower().Contains("png"))
{
resizedImg.Save(newFilename, ImageFormat.Png);
}
else if (fileNameExtension != null && fileNameExtension.ToLower().Contains("bmp"))
{
resizedImg.Save(newFilename, ImageFormat.Bmp);
}
else if (fileNameExtension != null && fileNameExtension.ToLower().Contains("ico"))
{
resizedImg.Save(newFilename, ImageFormat.Icon);
}
else if (fileNameExtension != null && fileNameExtension.ToLower().Contains("tiff"))
{
resizedImg.Save(newFilename, ImageFormat.Tiff);
}
else if (fileNameExtension != null && fileNameExtension.ToLower().Contains("emf"))
{
resizedImg.Save(newFilename, ImageFormat.Emf);
}
else if (fileNameExtension != null && fileNameExtension.ToLower().Contains("wmf"))
{
resizedImg.Save(newFilename, ImageFormat.Wmf);
}
else
{
success = false;
}
MessageBox.Show(success
? String.Format("Done! File saved as {0}", newFilename)
: "Something went awry. The file was not saved");
Recycle();
}
finally
{
Cursor.Current = Cursors.Default;
}
}
private void Recycle()
{
buttonResizeImage.Enabled = false;
buttonApplyPercentageChange.Enabled = false;
labelImgSelected.Text = "Image selected: ";
textBoxOrigHeight.Text = String.Empty;
textBoxOrigWidth.Text = String.Empty;
// Retain the percentage vals, as it may be that all in a batch need to be the same pair of vals
}
private void buttonApplyPercentageChange_Click(object sender, EventArgs e)
{
int origHeight = _imgToResize.Height;
int origWidth = _imgToResize.Width;
// Two ways to convert the val
double heightFactor = (double)numericUpDownHeight.Value / 100.0;
double widthFactor = Convert.ToDouble(numericUpDownWidth.Value) / 100.0;
if (heightFactor < 0 || widthFactor < 0)
{
// show an error - no negative values allowed- using updown, so that should not be possible
}
var newHeight = Convert.ToInt32(origHeight * heightFactor);
var newWidth = Convert.ToInt32(origWidth * widthFactor);
textBoxNewHeight.Text = newHeight.ToString();
textBoxNewWidth.Text = newWidth.ToString();
buttonResizeImage.Enabled = true;
}
private void textBoxNewHeight_TextChanged(object sender, EventArgs e)
{
EnableResizeButtonIfValidDimensionsEntered();
}
private void EnableResizeButtonIfValidDimensionsEntered()
{
if (String.IsNullOrWhiteSpace(textBoxOrigHeight.Text)) return;
String candidateHeight = textBoxNewHeight.Text;
String candidateWidth = textBoxNewWidth.Text;
int validHeight;
int validWidth;
buttonResizeImage.Enabled = (int.TryParse(candidateHeight, out validHeight)) &&
(int.TryParse(candidateWidth, out validWidth));
}
private void numericUpDownHeight_ValueChanged(object sender, EventArgs e)
{
if (checkBoxRetainRatio.Checked)
{
numericUpDownWidth.Value = numericUpDownHeight.Value;
}
}
private void numericUpDownWidth_ValueChanged(object sender, EventArgs e)
{
if (checkBoxRetainRatio.Checked)
{
numericUpDownHeight.Value = numericUpDownWidth.Value;
}
}
}
}
From the Image.Save documentation:
If no encoder exists for the file format of the image, the Portable
Network Graphics (PNG) encoder is used. When you use the Save method
to save a graphic image as a Windows Metafile Format (WMF) or Enhanced
Metafile Format (EMF) file, the resulting file is saved as a Portable
Network Graphics (PNG) file. This behavior occurs because the GDI+
component of the .NET Framework does not have an encoder that you can
use to save files as .wmf or .emf files.
If you want to save in a different format, use the overloaded Save method, taking format as a second parameter:
Save(String, ImageFormat)
Most image viewers don't use the extension of the file to determine the type of the file, but use so called "magic numbers" (http://en.wikipedia.org/wiki/Magic_number_(programming)#Magic_numbers_in_files). They basically check the first X bytes of the file wich is often unique to a specific image format.
My guess is, that the library you're using saves the file as PNG as default (edit: see Eugenes answer), not considering what extension you put there. IrfanView notices, that the magic number and the extension don't match but still shows the image by defaulting to the magic number.
Go to a console and print out the file. If it is a PNG file, you will see PNG displayed and it stops.
If is is JPEG, you will get a lot of garbage but should see EXIF or JFIF at the top. The very start is FF D8
Because the JPEG and PNG have different signatures, the application can tell them apart from their contents and invite the appropriate decoder.
Image applications normally identify the type of image from the contents of the stream, not the extension.
I have an OpenFileDialog in my WinForm and I want when to select an image to limit the image's size in 100 Ko and the Dimensions in 350x350.
How can I do that ??
private bool ValidFile(string filename, long limitInBytes, int limitWidth, int limitHeight)
{
var fileSizeInBytes = new FileInfo(filename).Length;
if(fileSizeInBytes > limitInBytes) return false;
using(var img = new Bitmap(filename))
{
if(img.Width > limitWidth || img.Height > limitHeight) return false;
}
return true;
}
private void selectImgButton_Click(object sender, EventArgs e)
{
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
if(ValidFile(openFileDialog1.FileName, 102400, 350, 350))
{
// Image is valid and U can
// Do something with image
// For example set it to a picture box
pictureBox1.Image = new Bitmap(openFileDialog1.FileName);
}
else
{
MessageBox.Show("Image is invalid");
}
}
}
It depends on what types of images you need to support. For most common types (bmp, jpg, png), you can easily retrieve image info:
string filename = // get it from OpenFileDialog
if (new FileInfo(filename).Length > SOME_LIMIT)
{
MessageBox.Show("!!!");
}
else
{
Image img = Image.FromFile(filename);
MessageBox.Show(string.Format("{0} x {1}", img.Width, img.Height));
}
If you need more extensive support for many image formats, then I suggest using a library like ImageMagick.NET
put this as global variable
int imgSize = 0
private void button1_Click(object sender, EventArgs e)
{
Image imageFile;
OpenFileDialog dlg = new OpenFileDialog();
dlg.Title = "Open Image";
dlg.Filter = "jpg files (*.jpg)|*.jpg|All files (*.*)|*.*";
if (dlg.ShowDialog() == DialogResult.OK)
{
imageFile = Image.FromFile(dlg.FileName);
imgHeight = imageFile.Height;
if (imgHeight > 350)
{
MessageBox.Show("Not 350x350 Image", "Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
imgPhoto.Image = null;
}
else
{
PictureBox1.Image = new Bitmap(dlg.OpenFile());
}
}
dlg.Dispose();
}
Hope this will help.
Try this :
OpenFileDialog fileDialog = new OpenFileDialog
{
// managed GDI+ supports bmp, jpeg, gif, png and tiff.
Filter =
"Image files (*.bmp;*.jpg;*.gif;*.png;*.tiff)|*.bmp;*.jpg;*.gif;*.png;*.tiff|All files (*.*)|*.*",
};
if (fileDialog.ShowDialog() == DialogResult.OK)
{
// Many exceptions could be raised in the following code
try
{
var fileSize = new FileInfo(fileDialog.FileName);
var validFilesize = fileSize.Length <= 1024 * 100; // 100 kilo bytes
var validDimensions = false;
// free the file once we get the dimensions
using (Image image = Image.FromFile(fileDialog.FileName))
{
validDimensions = (image.Width <= 350) && (image.Height <= 350);
}
if (!validDimensions || !validFilesize)
{
MessageBox.Show("Error ! Choose another image");
}
else
{
// do something with the file here
}
}
catch (Exception exception)
{
MessageBox.Show(exception.Message);
}
}
The error is on the line:
for (int x = 0; x < myList.Count(); x++)
The x++is painted with green.
Im using backgroundoworker and I used this code same code in another form before without a backgroundworker and it worked good. Now in the other form im using a click button event to show() this form and I want to use a progressBar1 to show the progress of the backgroundowrker work.
I used now try and catch inside this for loop and it went to the catch point and showed me the error. The full exception message is:
at System.Drawing.Image.Save(String filename, ImageCodecInfo encoder, EncoderParameters encoderParams)
at System.Drawing.Image.Save(String filename, ImageFormat format)
at mws.Animation_Radar_Preview.backGroundWorker1_DoWork(Object sender, DoWorkEventArgs e) in D:\C-Sharp\Download File\Downloading-File-Project-Version-012\Downloading File\Animation_Radar_Preview.cs:line 163
gifImages isnt null.
This is the full code of this form:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using DannyGeneral;
using unfreez_wrapper;
namespace mws
{
public partial class Animation_Radar_Preview : Form
{
int mtpStart;
int mtpEnd;
Picturebox1_Fullscreen pb1;
string radar_images_download_directory;
string tempRadarPngToGifDirectory;
int numberOfFiles;
UnFreezWrapper unfreez;
string path_exe;
List<string> myList;
string previewDirectory;
int animatedGifSpeed;
bool loop;
string nameOfStartFile;
string nameOfEndFile;
string previewFileName;
BackgroundWorker backGroundWorker1;
Image img;
private MemoryStream _memSt = null;
public Animation_Radar_Preview()
{
InitializeComponent();
mtpStart = Picturebox1_Fullscreen.mtp1Start;
mtpEnd = Picturebox1_Fullscreen.mtp1End;
animatedGifSpeed = Picturebox1_Fullscreen.animatedSpeed;
loop = Picturebox1_Fullscreen.looping;
pb1 = new Picturebox1_Fullscreen();
radar_images_download_directory = Options_DB.Get_Radar_Images_Download_Directory();
path_exe = Path.GetDirectoryName(Application.LocalUserAppDataPath);
tempRadarPngToGifDirectory = path_exe + "\\" + "tempRadarPngToGifDirectory";
if (Directory.Exists(tempRadarPngToGifDirectory))
{
}
else
{
Directory.CreateDirectory(tempRadarPngToGifDirectory);
}
previewDirectory = path_exe + "\\" + "previewDirectory";
if (Directory.Exists(previewDirectory))
{
}
else
{
Directory.CreateDirectory(previewDirectory);
}
previewFileName = previewDirectory + "\\" + "preview.gif";
loop = false;
animatedGifSpeed = 0;
unfreez = new UnFreezWrapper();
backGroundWorker1 = new BackgroundWorker();
backGroundWorker1.WorkerSupportsCancellation = true;
this.backGroundWorker1.WorkerReportsProgress = true;
backGroundWorker1.ProgressChanged += new ProgressChangedEventHandler(backGroundWorker1_ProgressChanged);
backGroundWorker1.DoWork += new DoWorkEventHandler(backGroundWorker1_DoWork);
backGroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backGroundWorker1_RunWorkerCompleted);
backGroundWorker1.RunWorkerAsync();
progressBar1.Value = 0;
}
private void button2_Click(object sender, EventArgs e)
{
DialogResult result1;
result1 = new DialogResult();
SaveFileDialog sd = new SaveFileDialog();
sd.Title = "Select a folder to save the animated gif to";
sd.InitialDirectory = "c:\\";
sd.FileName = null;
sd.Filter = "Gif File|*.gif;*.jpg|Gif|*.gif";
sd.FilterIndex = 1;
sd.RestoreDirectory = true;
result1 = sd.ShowDialog();
string file1 = sd.FileName;
if (result1 == DialogResult.OK)
{
File.Move(previewFileName, file1);
}
}
public void pictureBoxImage(string pbImage)
{
Image img2 = null;
try
{
using (img = Image.FromFile(pbImage))
{
//get the old image thats loaded from the _memSt memorystream
//and dispose it
Image i = this.pictureBox1.Image;
this.pictureBox1.Image = null;
if (i != null)
i.Dispose();
//grab the old stream
MemoryStream m = _memSt;
//save the new image to this stream
_memSt = new MemoryStream();
img.Save(_memSt, System.Drawing.Imaging.ImageFormat.Gif);
if (m != null)
m.Dispose();
//create our image to display
img2 = Image.FromStream(_memSt);
}
if (img2 != null)
pictureBox1.Image = img2;
label2.Text = numberOfFiles.ToString();
label6.Text = nameOfStartFile.ToString();
label4.Text = nameOfEndFile.ToString();
//File.Delete(pbImage);
}
catch(Exception err)
{
Logger.Write("Animation Error >>> " + err);
}
}
private void backGroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}
private void backGroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
List<string> myGifList;
Image gifImages = null;
//button1.Enabled = false;
Animation_Radar_Preview ap = new Animation_Radar_Preview();
//ap.FormClosing += new FormClosingEventHandler(ap_FormClosing);
FileInfo[] fi;
DirectoryInfo dir1 = new DirectoryInfo(radar_images_download_directory);
fi = dir1.GetFiles("*.png");
myList = new List<string>();
myGifList = new List<string>();
for (int i = mtpStart; i < mtpEnd; i++)
{
myList.Add(fi[i].FullName);
}
for (int x = 0; x < myList.Count(); x++)
{
try
{
gifImages = Image.FromFile(myList[x]);
gifImages.Save(tempRadarPngToGifDirectory + "\\" + x.ToString("D6") + ".Gif", System.Drawing.Imaging.ImageFormat.Gif);
}
catch (Exception ex)
{
MessageBox.Show(x.ToString() + "\r\n" + (gifImages == null).ToString() + "\r\n" + ex.Message);
}
}
myGifList = new List<string>();
dir1 = new DirectoryInfo(tempRadarPngToGifDirectory);
fi = dir1.GetFiles("*.gif");
nameOfStartFile = fi[0].Name;
for (int i = 0; i < fi.Length; i++)
{
myGifList.Add(fi[i].FullName);
//backGroundWorker1.ReportProgress(i);
nameOfEndFile = fi[i].Name.Length.ToString();
}
numberOfFiles = myGifList.Count();
unfreez.MakeGIF(myGifList, previewFileName, animatedGifSpeed, loop);
/*this.Invoke((MethodInvoker)delegate
{
pictureBoxImage(previewFileName);
});*/
}
private void backGroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
pictureBoxImage(previewFileName);
}
}
}
I'm not entirely sure what is going wrong, especially as you say this same code worked previously — but it is not clear whether it worked with the same set of images.
Anyhow, the documentation for the Save method says that an ExternalException will be thrown in one of two situations:
Image was saved with the wrong format.
Image is saved to the file it was created from.
It cannot be that you are saving over the file because you are changing its extension, so it must be the wrong format. What this actually means is not clear. Perhaps one of the source images is using capabilities of the PNG format that cannot be converted to GIF, e.g. alpha channel transparency.
If I may take a moment to make some other suggestions too:
if (Directory.Exists(tempRadarPngToGifDirectory))
{
}
else
{
Directory.CreateDirectory(tempRadarPngToGifDirectory);
}
The empty 'success' case is not required if you invert the logic:
if (!Directory.Exists(tempRadarPngToGifDirectory)
{
Directory.CreateDirectory(tempRadarPngToGifDirectory);
}
Code that manipulates file paths such as the following:
tempRadarPngToGifDirectory = path_exe + "\\" + "tempRadarPngToGifDirectory";
You should consider using the Path class as this will handle the edge cases better and make more portable code:
tempRadarPngToGifDirectory = Path.Combine(path_exe, "tempRadarPngToGifDirectory");