winforms keeps freezing -endless loop? how do i un-freeze? - c#

I have a program which displays an image to the windows form, and places a message within the image as it paints it (this works fine) i then have a method which reads the message back. However, doing this causes the winforms screen to freeze! i must be getting stuck in an endless loop. The method does work as i do get the message back.... can anyone help un-freeze my program?
Code below:
public partial class MyImages : Form
{
//I have variables related to encoding and decoding here(deleted)
private const String MESSAGE = "2008-01-07";
Bitmap firstLoaded;
Bitmap theImage;
Bitmap imageEmbedded;
Boolean isGetMessage = false;
Boolean isEmbedImage = false;
Boolean isLoaded = false;
Graphics graphicsWindow; // reference to the graphic surface of this window
Graphics graphicsImage; // reference to in-memory surface
BitArray bitsOfMessage = new BitArray(8);
String bytesOfTheMessage = null;
public MyImages()
{
InitializeComponent();
this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.DoubleBuffer, true);
}
private void MyImages_Paint(object sender, PaintEventArgs e)
{
HandlePainting();
}
public void HandlePainting()
{
if (isLoaded == true)
{
theImage = new Bitmap(Width, Height); // bitmap for window surface copy
graphicsWindow = CreateGraphics(); // get our current window's surface
graphicsImage = Graphics.FromImage(theImage); // create surfaces from the bitmaps
graphicsImage.DrawImage(firstLoaded, 0, 0, Width, Height);
if (isEmbedImage == true)
{
theImage = embedMessageInImage(theImage);
}
else if (isGetMessage == true)
{
getEmbeddedMessage(imageEmbedded);
}
if (isGetMessage == false)
{
graphicsWindow.DrawImage(theImage, 0, 0);
}
else if (isGetMessage == true)
{
graphicsWindow.DrawImage(imageEmbedded, 0, 0);
}
}
}
private void toolStripMenuItemLoadImage_Click(object sender, EventArgs e)
{
using (OpenFileDialog ofd = new OpenFileDialog())
{
ofd.Title = "Load Image";
if (ofd.ShowDialog() == DialogResult.OK)
{
firstLoaded = new Bitmap(ofd.FileName);
this.Invalidate();
}
}
isLoaded = true;
}
private void toolStripMenuEmbedMessage_Click(object sender, EventArgs e)
{
isEmbedImage = true;
isGetMessage = false;
this.Invalidate();
}
private void toolStripMenuItemGetMessage_Click(object sender, EventArgs e)
{
isEmbedImage = false;
isGetMessage = true;
this.Invalidate();
}
public void convertToChar(int byteChar)
{
char val = Convert.ToChar(byteChar);
String nextChar = val.ToString();
bytesOfTheMessage += nextChar;
}
private Bitmap embedMessageInImage(Bitmap bmp)
{
//Embed message in this method (deleted)
//unlock the bitmaps
newBitmap.UnlockBits(newData);
bmp.Save("tina.bmp");
bmp.UnlockBits(originalData);
newBitmap.Save("tina7.bmp");
imageEmbedded = newBitmap;
return newBitmap;
}
}
private void getEmbeddedMessage(Bitmap bmp)
{
unsafe
{
//create an empty bitmap the same size as original
Bitmap newBitmap = new Bitmap(bmp.Width, bmp.Height);
//lock the original bitmap in memory
System.Drawing.Imaging.BitmapData originalData = bmp.LockBits(
new Rectangle(0, 0, bmp.Width, bmp.Height),
System.Drawing.Imaging.ImageLockMode.ReadOnly,
System.Drawing.Imaging.PixelFormat.Format24bppRgb);
//lock the new bitmap in memory
System.Drawing.Imaging.BitmapData newData = newBitmap.LockBits(
new Rectangle(0, 0, bmp.Width, bmp.Height),
System.Drawing.Imaging.ImageLockMode.WriteOnly,
System.Drawing.Imaging.PixelFormat.Format24bppRgb);
//set the number of bytes per pixel
int pixelSize = 3;
for (int y = 0; y < bmp.Height; y++)
{
//get the data from the original image
byte* originalImageRow = (byte*)originalData.Scan0 + (y * originalData.Stride);
//get the data from the new image
byte* newImageRow = (byte*)newData.Scan0 + (y * newData.Stride);
for (int x = 0; x < bmp.Width; x++)
{
byte b = (byte)(originalImageRow[x * pixelSize + 0]); // B
getEachBitOfMessage(b, BLUE);
byte g = (byte)(originalImageRow[x * pixelSize + 1]); // G
getEachBitOfMessage(g, GREEN);
byte r = ((byte)(originalImageRow[x * pixelSize + 2])); //R
getEachBitOfMessage(r, RED);
}
}
//unlock the bitmaps
newBitmap.UnlockBits(newData);
bmp.UnlockBits(originalData);
}
}
public byte changeEachBit(byte byteToManipulate, int colour, byte theMessage)
{
byte value = 0;
byte returnByte = 0;
if (colour == BLUE)
{
value= (byte)(theMessage & BValueMask);
value = (byte)(value>>5);
returnByte = (byte)(byteToManipulate & BlueMask);
returnByte = (byte)(returnByte | value);
}
else if (colour == GREEN)
{
value = (byte)(theMessage & GValueMask);
value = (byte)(value >> 3);
returnByte = (byte)(byteToManipulate & GreenMask);
returnByte = (byte)(returnByte | value);
}
else if (colour == RED)
{
value = (byte)(theMessage & RValueMask);
returnByte = (byte)(byteToManipulate & RedMask);
returnByte = (byte)(returnByte | value);
}
return returnByte;
}
public void getEachBitOfMessage(byte byteToManipulate, int colour)
{
//I Input bits into image here (deleted)
}
}
}

Let it freeze and click the Pause button on the top toolbar.
This will cause the debugger to break wherever execution may be, and you can then easily identify where it got stuck, and try and find out why as well (don't forget to watch values using the watch window or hovering them).

Related

How can I use graphics method for AForge IntPoint truely?

I tried to write a code for detecting elips objects with Aforge blobcounter function but when I want to draw it with graphics I am getting an error.
The error is:
Argument 2:cannot covert from 'AForge.IntPoint' to 'System.Drawing.PointF'.What is the thing that I am doing wrong and how can I fix it?
Here is the code:
namespace blobdnm
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
OpenFileDialog sfd = new OpenFileDialog();
sfd.Filter = "Image Files|*.bmp|All Files|*.*";
sfd.InitialDirectory = ".";
if (sfd.ShowDialog() != DialogResult.OK)
{
return;
}
pictureBox1.ImageLocation = sfd.FileName;
}
private void button2_Click(object sender, EventArgs e)
{
Bitmap bmp = new Bitmap(pictureBox1.Image);
BitmapData BmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
byte[] data = new byte[bmp.Width*bmp.Height*3];
IntPtr ptr = BmpData.Scan0;
Marshal.Copy(ptr, data, 0, data.Length);
for (int i = 0; i < bmp.Width*bmp.Height*3; i=i+3)
{
double a = data[i] * 0.2125 + data[i + 1] * 0.7154 + data[i + 2] *0.0721;
if(a>100)
{
data[i] = 0;
data[i+1] = 0;
data[i+2] = 0;
}
}
Bitmap bmp2 = new Bitmap(bmp.Width,bmp.Height,PixelFormat.Format24bppRgb);
BitmapData BmpData2 = bmp2.LockBits(new Rectangle(0, 0, bmp2.Width, bmp2.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
Marshal.Copy(data, 0,BmpData2.Scan0, data.Length);
bmp2.UnlockBits(BmpData2);
ColorFiltering colorFilter = new ColorFiltering();
BlobCounter blobCounter = new BlobCounter();
blobCounter.FilterBlobs = true;
blobCounter.MinWidth = 5;
blobCounter.MinHeight = 5;
blobCounter.MaxWidth = 3000;
blobCounter.MaxHeight = 3000;
blobCounter.ProcessImage(BmpData2);
Blob[] blobs = blobCounter.GetObjectsInformation();
Graphics g = Graphics.FromImage(bmp2);
Pen redPen = new Pen(Color.Red, 2);
List<IntPoint> edgePoints=null;
for (int i = 0; i < blobs.Length; i++)
{
edgePoints = blobCounter.GetBlobsEdgePoints(blobs[i]);
for (int k = 0; k < edgePoints.Count; k++)
{
g.DrawPolygon(redPen, edgePoints[k]); //This is the part that I am getting an error
}
}
redPen.Dispose();
g.Dispose();
pictureBox1.Image = bmp2;
}
private System.Drawing.Point[] ToPointsArray(List<IntPoint> points)
{
System.Drawing.Point[] array = new System.Drawing.Point[points.Count];
for (int i = 0, n = points.Count; i < n; i++)
{
array[i] = new System.Drawing.Point(points[i].X, points[i].Y);
}
return array;
}
}
}
You have to convert AForge.IntPoint into System.Drawing.Point and then pass it to Graphics.DrawPolygon() method.
This will do the job:
public System.Drawing.Point ToPoint(IntPoint point)
{
return new System.Drawing.Point(point.X, point.Y);
}
In fact you have method ToPointsArray() doing the same conversion but on the list of IntPoint in your code.

Break cycles without leaks

I have simple code that trying to find sequence of pixel on the screen.
How two break two cycles without memory leaks in function FindPixelSequence
when if (isEqual) occures?
How to improve existing code?
namespace FindColor
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
PlayWithColor PWC = new PlayWithColor();
List<System.Drawing.Color> pixels { get; set; }
public MainWindow()
{
InitializeComponent();
pixels = new List<System.Drawing.Color>();
pixels.Add(System.Drawing.Color.FromArgb(0, 0, 0, 0));
pixels.Add(System.Drawing.Color.FromArgb(0, 153, 255, 0));
pixels.Add(System.Drawing.Color.FromArgb(0, 153, 255, 0));
pixels.Add(System.Drawing.Color.FromArgb(0, 128, 214, 0));
}
private void Button_Click(object sender, RoutedEventArgs e)
{
using (var bitmap = PWC.TakeScreen())
{
PWC.FindPixelSequence(bitmap, pixels);
}
}
}
class ColorEqualityComparer : IEqualityComparer<Color>
{
public bool Equals(Color b1, Color b2)
{
return b1.R == b2.R && b1.G == b2.G && b1.B == b2.B;
}
public int GetHashCode(Color obj)
{
throw new NotImplementedException();
}
}
public class PlayWithColor
{
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern bool SetCursorPos(int x, int y);
private Bitmap bmpScreenshot { get; set; }
public Bitmap TakeScreen()
{
bmpScreenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width,
Screen.PrimaryScreen.Bounds.Height,
PixelFormat.Format32bppArgb);
var gfxScreenshot = Graphics.FromImage(bmpScreenshot);
int sourceX = Screen.PrimaryScreen.Bounds.X;
int sourceY = Screen.PrimaryScreen.Bounds.Y;
gfxScreenshot.CopyFromScreen(sourceX,
sourceY,
0,
0,
Screen.PrimaryScreen.Bounds.Size,
CopyPixelOperation.SourceCopy);
return bmpScreenshot;
}
public System.Drawing.Point? FindPixelSequence(Bitmap bitmap, List<Color> pixels)
{
Stopwatch watch = new Stopwatch();
List<Color> currentPixels;
watch.Start();
BitmapData data = bitmap.LockBits(new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
unsafe
{
byte* ptrSrc = (byte*)data.Scan0;
for (int y = 0; y < data.Height; y = y + 1)
{
for (int x = 0; x < data.Width; x = x + 1)
{
currentPixels = new List<Color>();
for (int i = 0; i < pixels.Count; i++)
{
byte r0 = ptrSrc[2];
byte g0 = ptrSrc[1];
byte b0 = ptrSrc[0];
Color currentPixel = Color.FromArgb(0, r0, g0, b0);
ptrSrc += 4;
currentPixels.Add(currentPixel);
}
ptrSrc -= (4 * (pixels.Count - 1));
bool isEqual = currentPixels.SequenceEqual(pixels, new ColorEqualityComparer());
if (isEqual)
{
SetCursorPos(x, y);
//how return coords of x and y from there?
}
}
}
}
bitmap.UnlockBits(data);
watch.Stop();
Debug.WriteLine(watch.ElapsedMilliseconds);
}
}
}
for the unsafe code surround it with a try finally , to always unlock the bitmap and release any memory you allocated internally
1.
unsafe
{
Stopwatch watch = new Stopwatch();
watch.Start();
try
{
....
return new Point(x,y); // To return x,y corrdinates
}
finally
{
bitmap.UnlockBits(data);
watch.Stop();
}
}
to simply the code I would use a 3rd party image tool software library for c# you have AForge.NET

Can't resize the changed image? C# WinForms

If i change the colour of the image and then try to resize, it only resizes the original image. Why is this happening and how do i fix it?
Here is my code:
private PrintDocument printDoc = new PrintDocument();
private PageSettings pgSettings = new PageSettings();
private PrinterSettings prtSettings = new PrinterSettings();
Bitmap myBitmapImage; // image (bitmap) for some background mountains
Boolean isInvert = false;
Boolean isLOaded = false;
Boolean isGrayscale = false;
Boolean isThreshold = false;
Boolean isResize = false;
OpenFileDialog ofd;
Bitmap bmBack;
public EditImage()
{
printDoc.PrintPage += new PrintPageEventHandler(printDoc_PrintPage);
InitializeComponent();
this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.DoubleBuffer, true);
}
private void EditImage_Load(object sender, EventArgs e)
{
}
private void EditImage_Paint(object sender, PaintEventArgs e)
{
if (isLOaded == true)
{
Graphics gWindow; // reference to the graphic surface of this window
Graphics gBack; // reference to in-memory surface
bmBack = new Bitmap(Width, Height); // bitmap for window surface copy
gWindow = e.Graphics; // get our current window's surface
gBack = Graphics.FromImage(bmBack); // create surfaces from the bitmaps
gBack.DrawImage(myBitmapImage, 0, 0, Width, Height);
if (isInvert == true)
{
InvertBitmap(bmBack);
}
else if (isGrayscale == true)
{
GrayscaleBitmap(bmBack);
}
else if (isThreshold == true)
{
ThresholdBitmap(bmBack);
}
else if (isResize == true)
{
bmBack = resizeImage(bmBack, 10, 100);
}
gWindow.DrawImage(bmBack, 0, 0);
}
}
private void toolStripMenuItemLoadImage_Click(object sender, EventArgs e)
{
using (ofd = new OpenFileDialog())
{
ofd.Title = "Load Image";
if (ofd.ShowDialog() == DialogResult.OK)
{
myBitmapImage = new Bitmap(ofd.FileName);
this.Invalidate();
}
}
isLOaded = true;
}
private void GrayscaleBitmap(Bitmap bmp)
{
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
System.Drawing.Imaging.BitmapData bmpData = bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite,
System.Drawing.Imaging.PixelFormat.Format32bppRgb);
IntPtr ptr = bmpData.Scan0;
int numPixels = bmpData.Width * bmp.Height;
int numBytes = numPixels * 4;
byte[] rgbValues = new byte[numBytes];
System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, numBytes);
for (int i = 0; i < rgbValues.Length; i += 4)
{
byte gray = (byte)(.3 * rgbValues[i + 0]); //blue
gray += (byte)(.59 * rgbValues[i + 1]); //green
gray += (byte)(.11 * rgbValues[i + 2]); //red
rgbValues[i + 0] = gray; //blue
rgbValues[i + 1] = gray; //green
rgbValues[i + 2] = gray; //red
}
System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, numBytes);
bmp.UnlockBits(bmpData);
}
private Bitmap resizeImage(Bitmap sourceBMP, int width, int height)
{
Bitmap result = new Bitmap(width, height);
using(Graphics g = Graphics.FromImage(result))
g.DrawImage(sourceBMP, 0, 0, width, height);
return result;
}
i also have methods which deal with when the user clicks on a button and sets the bools to appropriate values so that it calls the correct method. The images DO change colour - as intended.. but when i click on resize, i want it to resize the version of the image that has changed colour - not the original image...
There are lots of things wrong here:
resizeImage()
You should dispose of the Graphics object that you create here (wrap it in a using() statement)
Don't call invalidate from here, this function just resizes your image, you invalidate after you've changed your image and your Paint method paints the image which has now changed.
You should also think about disposing of the sourceBMP right before you return the function if you no longer have any use for it.
GrayscaleBitmap()
This looks right, but again there's no reason to invalidate here. You should invalidate after you call this method in the calling function. It makes more sense.
EditImage_Paint
You should not be calling these functions from within your Paint event. And you should not be creating a new Bitmap and a new Graphics class on each Paint. This is way more work than necessary. These functions should only execute when the data needs to be changed based on user input (user clicks a button to apply a grayscale effect).
For what you want to do, you should only need 2 bitmap variables at most. One to store the original unmodified bitmap in case you want to let the user "Reset" it or to undo any effects (most effects cause permanent data loss, you can't make a grayscale image color again). And the other to store the bitmap that gets painted. Each time the user applies an effect, it modifies the 2nd bitmap, and then calls invalidate.
All your Paint function should do is paint the 2nd bitmap:
Bitmap originalBitmap; // load from file, do not modify
Bitmap currentBitmap; // when user clicks an effect, modify this bitmap and then Invalidate afterward
private void EditImage_Paint(object sender, PaintEventArgs e)
{
e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
// Draw the currentBitmap centered on the window
SizeF clientSize = this.ClientSize;
double zoomRatio = Math.Min(
clientSize.Width / currentBitmap.Width,
clientSize.Height / currentBitmap.Height
);
SizeF zoomedSize = new SizeF(
(float)(currentBitmap.Width * zoomRatio),
(float)(currentBitmap.Height * zoomRatio)
);
PointF imageOffset = new PointF(
(clientSize.Width - zoomedSize.Width) / 2,
(clientSize.Height - zoomedSize.Height) / 2
);
e.Graphics.Clear(Color.White);
e.Graphics.DrawImage(currentBitmap, imageOffset.X, imageOffset.Y, zoomedSize.Width, zoomedSize.Height);
}
This emulates a simple zoom effect that centers the image on the control and draws it to fit the window.

Clean up the surface on WaterMark of an Image

There is an image for the surface, and a text is written on the image for 184 rows of date..
Thus, it is expected to see 184 different text written image files are generated with all the same background images. (The code is declared below...)
The problem is that the first text is written for all 184 different data.. I think I have to remove something in the loop. But what is that ??
for (int i = 0; i < dt.Rows.Count; i++) {
date = Convert.ToDateTime(dt.Rows[i]["PAYMENT_DATE"]);
branchCode = Convert.ToInt32(dt.Rows[i]["BRANCH_CODE"]);
refNum = Convert.ToInt32(dt.Rows[i]["REF_NUM"]);
accountNumber = Convert.ToInt32(dt.Rows[i]["ACCOUNT_NUMBER"]);
email = dt.Rows[i]["EMAIL"].ToString();
tableCode = dt.Rows[i]["CUSTOMER_TABLE_CODE"].ToString();
TranLogKey logKey = new TranLogKey(date, branchCode, refNum);
TranLogEntry entry = Log.SelectLogEntry(logKey, false);
if (Intertech.Core.Framework.Context.CurrentContext.LogEntry == null)
Intertech.Core.Framework.Context.CurrentContext.LogEntry = entry;
try {
receiptText = TransactionManager.GenerateReceipt(true, logKey, null, null, accountNumber, false);
}
catch (Exception exp) {
continue;
}
if (receiptText != null) {
if (receiptText.IndexOf("SURETTİR\r\n") != -1)
receiptText = receiptText.Substring(receiptText.IndexOf("SURETTİR\r\n") + 10).Trim();
if (receiptText.IndexOf("İşlemi Yapan") != -1)
receiptText = receiptText.Substring(0, receiptText.IndexOf("İşlemi Yapan"));
if (receiptText.IndexOf("MÜŞTERİ İMZASI") != -1)
receiptText = receiptText.Substring(0, receiptText.IndexOf("MÜŞTERİ İMZASI"));
Bitmap bmp = (Bitmap)Bitmap.FromFile(imageDir);
Graphics g = Graphics.FromImage(bmp);
SizeF size;
Font font = new Font("Courier New", 8, FontStyle.Regular);
byte ALPHA = 200;
size = g.MeasureString(receiptText, font);
Bitmap waterbmp = new Bitmap((int)size.Width, (int)size.Height);
Graphics waterg = Graphics.FromImage(waterbmp);
waterg.DrawString(receiptText, font, new SolidBrush(System.Drawing.Color.Black), 2, 2);
DrawWatermark(ref waterbmp, ref bmp, LeftIndex, TopIndex, ALPHA);
bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
try {
GoServices.Core.SendMailOutside("The Portugal Life", "info#portugal.tr.friendship.pt",
"blgnklc#skype-account.com", " e-Wish " + email, "", new string[] { "dekont.jpg" }, new object[] { ms.ToArray() });
LogNotificationState("K", refNum, accountNumber, 2, true, null, tableCode);
}
catch (Exception ex) {
LogNotificationState("K", 0, -1, 2, false, ex, tableCode);
}
}
private static void DrawWatermark(ref Bitmap watermark_bm, ref Bitmap result_bm, int x, int y, byte ALPHA) {
System.Drawing.Color clr;
int py, px;
for (py = 0; py <= watermark_bm.Height - 1; py++) {
for (px = 0; px <= watermark_bm.Width - 1; px++) {
clr = watermark_bm.GetPixel(px, py);
if (clr.A != 0 || clr.R != 0 || clr.G != 0 || clr.B != 0)
watermark_bm.SetPixel(px, py, System.Drawing.Color.FromArgb(ALPHA, clr.R, clr.G, clr.B));
}
}
Graphics gr = Graphics.FromImage(result_bm);
gr.DrawImage(watermark_bm, x, y);
}
I would look at how you are creating the bitmap.
Bitmap bmp = (Bitmap)Bitmap.FromFile(imageDir);
does this line need to be in there everytime, i.e is imagedir the same all the time?
Do you dispose of the generated bitmap after creating it?
what happens in this function:
DrawWatermark(ref waterbmp, ref bmp, LeftIndex, TopIndex, ALPHA);
You seem to then save the bmp file but not dispose of it?
I have seen some strange behaviour from GDI+ so I would start here.

C# Very Simple Image Resizer

I am in need of a very simple c# image resizer. By simple, I mean simple. This is just a program that loops through a single directory and changes all the pictures in that directory to the same resolution. Here's what I have so far.
private void Form1_Load(object sender, EventArgs e)
{
string[] files = null;
int count = 0;
files = System.IO.Directory.GetFiles(#"C:\Users\..\..\ChristmasPicsResized");
foreach (string file in files)
{
System.Drawing.Bitmap bmp = System.Drawing.Bipmap.FromFile(file);
ResizeBitmap(bmp, 807, 605);
bmp.Save(file);
count++;
lblCount.Text = count.ToString();
}
}
public Bitmap ResizeBitmap(Bitmap b, int nWidth, int nHeight)
{
Bitmap result = new Bitmap(nWidth, nHeight);
using (Graphics g = Graphics.FromImage((Image)result))
g.DrawImage(b, 0, 0, nWidth, nHeight);
return result;
}
The problem I ran into is that the picture cannot be saved while it is open. I am unsure how to make this into a file stream. What should be a very simple app doesn't seem so simple to me. Any help please?
Try saving to a temp file, then delete the original file and rename the temp file to the original file name.
Have a look at C# Image to Byte Array and Byte Array to Image Converter Class
public byte[] imageToByteArray(System.Drawing.Image imageIn)
{
MemoryStream ms = new MemoryStream();
imageIn.Save(ms,System.Drawing.Imaging.ImageFormat.Gif);
return ms.ToArray();
}
and
public Image byteArrayToImage(byte[] byteArrayIn)
{
MemoryStream ms = new MemoryStream(byteArrayIn);
Image returnImage = Image.FromStream(ms);
return returnImage;
}
This way you can close the image after you have read it in, and can then save it over the existing one.
You could also render the resized images into a different folder to preserve the original, high-resolution images. Maybe you'll need them one day (i did that mistake once...).
I created this nuget package which does resizing for you:
http://nuget.org/packages/Simple.ImageResizer
Source and howto here:
https://github.com/terjetyl/Simple.ImageResizer
My C# Image Extension class:
namespace MycImageExtension
{
public static class Helper
{
public static Image Clip(this Image imgPhoto, int width, int height)
{
return Clip(imgPhoto, width, height, false);
}
public static Image ToImage(this byte[] ba)
{
var ms = new MemoryStream(ba);
return Image.FromStream(ms);
}
public static byte[] ToArray(this Image imgPhoto)
{
var ms = new MemoryStream();
imgPhoto.Save(ms, ImageFormat.Jpeg);
return ms.ToArray();
}
static ImageCodecInfo GetImageCodec(string mimetype)
{
foreach (ImageCodecInfo ici in ImageCodecInfo.GetImageEncoders())
{
if (ici.MimeType == mimetype) return ici;
}
return null;
}
public static Image Clip(this Image imgPhoto, int width, int height, bool stretch)
{
if (!stretch && (imgPhoto.Width <= width && imgPhoto.Height <= height))
return imgPhoto;
// detect if portrait
if (imgPhoto.Height > imgPhoto.Width)
{
// swap
int a = width;
width = height;
height = a;
}
var d = new Dimension(imgPhoto.Width, imgPhoto.Height);
double scale = d.NewSizeScaleFactor(new Dimension(width, height), stretch);
var newD = scale * d;
if (stretch)
{
if (!(newD.Width == width || newD.Height == height))
throw new Exception("Stretching algo has some error");
}
var bmPhoto = new Bitmap(imgPhoto, new Size(newD.Width, newD.Height));
return bmPhoto;
}
// using for crystal report
public static Image PadImage(this Image imgPhoto, int width, int height)
{
// detect if portrait
if (imgPhoto.Height > imgPhoto.Width)
{
// swap
int a = width;
width = height;
height = a;
}
var d = new Dimension(imgPhoto.Width, imgPhoto.Height);
double scale = d.NewSizeScaleFactor(new Dimension(width, height), true);
Dimension newSize = scale * d;
PadAt padAt;
int padNeeded;
newSize.GetPadNeeded(new Dimension(width, height), out padAt, out padNeeded);
int padLeft = 0, padTop = 0;
if (padAt == PadAt.Width)
padLeft = padNeeded;
else if (padAt == PadAt.Height)
padTop = padNeeded;
var bmPhoto = new Bitmap(width, height, PixelFormat.Format24bppRgb);
var grPhoto = Graphics.FromImage(bmPhoto);
grPhoto.Clear(Color.White);
grPhoto.InterpolationMode = InterpolationMode.HighQualityBicubic;
grPhoto.DrawImage(imgPhoto,
new Rectangle(padLeft, padTop, newSize.Width, newSize.Height),
new Rectangle(0, 0, imgPhoto.Width, imgPhoto.Height),
GraphicsUnit.Pixel);
grPhoto.Dispose();
return bmPhoto;
}
}
public enum PadAt { None = 0, Width = 1, Height }
public struct Dimension
{
public int Width { set; get; }
public int Height { set; get; }
public Dimension(int width, int height)
: this()
{
this.Width = width;
this.Height = height;
}
public override string ToString()
{
return string.Format("Width: {0} Height: {1}", Width, Height);
}
public static Dimension operator *(Dimension src, double scale)
{
return new Dimension((int)Math.Ceiling((scale * src.Width)), (int)Math.Ceiling((scale * src.Height)));
}
public static Dimension operator *(double scale, Dimension src)
{
return new Dimension((int)Math.Ceiling((scale * src.Width)), (int)Math.Ceiling((scale * src.Height)));
}
public double NewSizeScaleFactor(Dimension newSize, bool stretch)
{
if (!stretch
&&
(this.Width <= newSize.Width && this.Height <= newSize.Height))
return 1;
double widthScaleFactor = (double)newSize.Width / this.Width;
double heightScaleFactor = (double)newSize.Height / this.Height;
// return the lowest scale factor
if (widthScaleFactor < heightScaleFactor)
return widthScaleFactor;
else if (heightScaleFactor < widthScaleFactor)
return heightScaleFactor;
else
return widthScaleFactor; // can even use heightscalefactor
}
public Dimension Clip(Dimension newSize, bool stretch)
{
if (!stretch
&&
(this.Width <= newSize.Width && this.Height <= newSize.Height))
return new Dimension(this.Width, this.Height);
double smallestScaleFactor = NewSizeScaleFactor(newSize, stretch);
return new Dimension((int)(this.Width * smallestScaleFactor), (int)(this.Height * smallestScaleFactor));
}
// so crystal report images would have exact dimension
public void GetPadNeeded(Dimension newSize, out PadAt padAt, out int padNeeded)
{
if (this.Width == newSize.Width && this.Height == newSize.Height)
{
padAt = PadAt.None;
padNeeded = 0;
return;
}
if (this.Width > newSize.Width || this.Height > newSize.Height)
throw new Exception("Source cannot be bigger than the new size");
if (this.Width != newSize.Width && this.Height != newSize.Height)
throw new Exception("At least one side should be equal");
if (newSize.Width != this.Width)
{
padAt = PadAt.Width;
padNeeded = (newSize.Width - this.Width) / 2;
}
else if (newSize.Height != this.Width)
{
padAt = PadAt.Height;
padNeeded = (newSize.Height - this.Height) / 2;
}
else
{
throw new Exception("Some anomaly occured, contact the programmer");
}
}
// test the logic
static void X()
{
var ls = new Dimension[]
{
new Dimension(400, 400), // as is
new Dimension(640, 480), // as is
new Dimension(600, 480), // as is
new Dimension(800, 600), // as is
new Dimension(800, 400), // as is
new Dimension(1280, 960), // as is
new Dimension(1280, 961), // as is
new Dimension(1281, 960), // as is
new Dimension(1280, 900), // as is
new Dimension(1000, 960), // as is
new Dimension(1000, 970), // as is
new Dimension(1000, 900), // as is
new Dimension(1380, 960), // clip
new Dimension(1280, 1000), // clip
new Dimension(1380, 1300), // clip
new Dimension(1600, 1200), // clip
new Dimension(1600, 1000), // clip
new Dimension(1800, 1200), // clip
new Dimension(1800, 1000), // clip
new Dimension(1400, 1200), // clip
new Dimension(1400, 1000), // clip
new Dimension(960, 1280), // clip
new Dimension(960, 1300), // clip
new Dimension(970, 1280) // clip
};
foreach (var l in ls)
{
// saving to database...
double scale = l.NewSizeScaleFactor(new Dimension(1280, 960), false);
Dimension newSize = scale * l;
// ...saving to database
// display to crystal report...
double scaleA = l.NewSizeScaleFactor(new Dimension(800, 600), true);
Dimension newSizeA = scaleA * l;
PadAt padAt;
int padNeeded;
newSizeA.GetPadNeeded(new Dimension(800, 600), out padAt, out padNeeded);
// ...display to crystal report
Console.WriteLine("Pad {0} {1}", padAt, padNeeded);
Console.WriteLine();
}
Console.ReadLine();
}
}
}

Categories

Resources